summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEgidijus Vaishnora2010-10-04 05:00:27 (EDT)
committerEgidijus Vaishnora2010-10-04 05:00:27 (EDT)
commit0ddddb416ca7297aeeb4ff6862e123ef3bdc77a0 (patch)
tree0df3e2b00925801f894d6b231a9ebe921e89cd69
parent6e1c2bde358ca46e8210dd40c81fb2c87a2c9089 (diff)
downloadcdo-0ddddb416ca7297aeeb4ff6862e123ef3bdc77a0.zip
cdo-0ddddb416ca7297aeeb4ff6862e123ef3bdc77a0.tar.gz
cdo-0ddddb416ca7297aeeb4ff6862e123ef3bdc77a0.tar.bz2
Bug fix https://bugs.eclipse.org/bugs/show_bug.cgi?id=324950
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDODetachedRevisionDeltaImpl.java81
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOMoveFeatureDeltaImpl.java20
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORemoveFeatureDeltaImpl.java3
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORevisionDeltaImpl.java3
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java4
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverTest.java4
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_316887_Test.java129
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_324544_Test.java56
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java4
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOTransaction.java1
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDONotificationBuilder.java133
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStore.java4
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java71
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/AbstractObjectConflictResolver2.java243
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOConflictResolver2.java45
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java76
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java54
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java4
18 files changed, 800 insertions, 135 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDODetachedRevisionDeltaImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDODetachedRevisionDeltaImpl.java
new file mode 100644
index 0000000..249f231
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDODetachedRevisionDeltaImpl.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.internal.common.revision.delta;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+
+import org.eclipse.emf.ecore.EClass;
+
+import java.util.List;
+
+/**
+ * @author Eike Stepper
+ */
+public class CDODetachedRevisionDeltaImpl implements CDORevisionDelta
+{
+ /**
+ * This constant is only passed into conflict resolvers to indicate that a conflict was caused by remote detachment of
+ * an object. Calling any method on this marker instance will result in an {@link UnsupportedOperationException} being
+ * thrown.
+ *
+ * @since 3.0
+ */
+ public static final CDORevisionDelta DETACHED = new CDODetachedRevisionDeltaImpl();
+
+ public CDODetachedRevisionDeltaImpl()
+ {
+ }
+
+ public CDOID getID()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public CDOBranch getBranch()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getVersion()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public EClass getEClass()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isEmpty()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public List<CDOFeatureDelta> getFeatureDeltas()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void apply(CDORevision revision)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void accept(CDOFeatureDeltaVisitor visitor)
+ {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOMoveFeatureDeltaImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOMoveFeatureDeltaImpl.java
index 5ef4214..fcc868d 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOMoveFeatureDeltaImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOMoveFeatureDeltaImpl.java
@@ -18,9 +18,9 @@ import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDOFeatureDelta.ListIndexAffecting;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDOFeatureDelta.WithIndex;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EStructuralFeature;
@@ -38,11 +38,14 @@ public class CDOMoveFeatureDeltaImpl extends CDOFeatureDeltaImpl implements CDOM
private int newPosition;
+ private Object value;
+
public CDOMoveFeatureDeltaImpl(EStructuralFeature feature, int newPosition, int oldPosition)
{
super(feature);
this.newPosition = newPosition;
this.oldPosition = oldPosition;
+ value = UNKNOWN_VALUE;
}
public CDOMoveFeatureDeltaImpl(CDODataInput in, EClass eClass) throws IOException
@@ -50,6 +53,7 @@ public class CDOMoveFeatureDeltaImpl extends CDOFeatureDeltaImpl implements CDOM
super(in, eClass);
newPosition = in.readInt();
oldPosition = in.readInt();
+ value = UNKNOWN_VALUE;
}
@Override
@@ -75,9 +79,21 @@ public class CDOMoveFeatureDeltaImpl extends CDOFeatureDeltaImpl implements CDOM
return Type.MOVE;
}
+ public Object getValue()
+ {
+ return value;
+ }
+
+ public void setValue(Object value)
+ {
+ this.value = value;
+ }
+
public CDOFeatureDelta copy()
{
- return new CDOMoveFeatureDeltaImpl(getFeature(), newPosition, oldPosition);
+ CDOFeatureDelta copy = new CDOMoveFeatureDeltaImpl(getFeature(), newPosition, oldPosition);
+ ((CDOMoveFeatureDeltaImpl)copy).setValue(getValue());
+ return copy;
}
public void apply(CDORevision revision)
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORemoveFeatureDeltaImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORemoveFeatureDeltaImpl.java
index 1cb4c99..6fdc941 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORemoveFeatureDeltaImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORemoveFeatureDeltaImpl.java
@@ -17,8 +17,8 @@ import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDOFeatureDelta.ListIndexAffecting;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EStructuralFeature;
@@ -44,6 +44,7 @@ public class CDORemoveFeatureDeltaImpl extends CDOSingleValueFeatureDeltaImpl im
@Override
protected void writeValue(CDODataOutput out, EClass eClass) throws IOException
{
+ // Do nothing
}
@Override
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORevisionDeltaImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORevisionDeltaImpl.java
index a008856..4a1b8f0 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORevisionDeltaImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDORevisionDeltaImpl.java
@@ -319,7 +319,8 @@ public class CDORevisionDeltaImpl implements InternalCDORevisionDelta
int index)
{
CDORemoveFeatureDeltaImpl delta = new CDORemoveFeatureDeltaImpl(feature, index);
- delta.setValue(value);
+ // fix until ListDifferenceAnalyzer delivers the correct value (bug #308618).
+ delta.setValue(oldList.get(index));
changes.add(delta);
oldList.remove(index);
}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
index 2b60415..5133de6 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
@@ -79,6 +79,7 @@ import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_314264_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_315043_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_316145_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_316434_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_316887_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_318844_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_318876_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_319836_Test;
@@ -87,6 +88,7 @@ import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_321699_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_322218_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_322754_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_323958_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_324544_Test;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTestSuite;
@@ -237,6 +239,8 @@ public abstract class AllConfigs extends ConfigTestSuite
testClasses.add(Bugzilla_322218_Test.class);
testClasses.add(Bugzilla_322754_Test.class);
testClasses.add(Bugzilla_323958_Test.class);
+ testClasses.add(Bugzilla_316887_Test.class);
+ testClasses.add(Bugzilla_324544_Test.class);
// TODO testClasses.add(NonCDOResourceTest.class);
// TODO testClasses.add(GeneratedEcoreTest.class);
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverTest.java
index 82d71fb..51b8134 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ConflictResolverTest.java
@@ -16,6 +16,8 @@ import org.eclipse.emf.cdo.tests.model1.Address;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CDOUtil;
+import org.eclipse.emf.internal.cdo.transaction.AbstractObjectConflictResolver2;
+
import org.eclipse.emf.spi.cdo.AbstractObjectConflictResolver.MergeLocalChangesPerFeature;
/**
@@ -75,7 +77,7 @@ public class ConflictResolverTest extends AbstractCDOTest
transaction.commit();
CDOTransaction transaction2 = session.openTransaction();
- transaction2.options().addConflictResolver(new MergeLocalChangesPerFeature());
+ transaction2.options().addConflictResolver(new AbstractObjectConflictResolver2.MergeLocalChangesPerFeature());
final Address address2 = (Address)transaction2.getOrCreateResource("/res1").getContents().get(0);
address2.setCity("OTTAWA");
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_316887_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_316887_Test.java
new file mode 100644
index 0000000..9648478
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_316887_Test.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDOFeatureDelta.WithIndex;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.TestAdapter;
+import org.eclipse.emf.cdo.tests.model2.Task;
+import org.eclipse.emf.cdo.tests.model2.TaskContainer;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+
+import org.eclipse.emf.internal.cdo.transaction.AbstractObjectConflictResolver2;
+
+import org.eclipse.emf.common.notify.Notification;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Databinding & CDO Notifications.
+ * <p>
+ * See bug 316887
+ *
+ * @author Cyril Jaquier
+ */
+public class Bugzilla_316887_Test extends AbstractCDOTest
+{
+ public void testResolveConflictWithAdjustedNotifcations() throws Exception
+ {
+ // setup transaction.
+ final CDOSession session = openSession();
+ final CDOTransaction tr1 = session.openTransaction();
+
+ final CDOResource resource = tr1.createResource("/test1");
+ TaskContainer container = getModel2Factory().createTaskContainer();
+ resource.getContents().add(container);
+
+ for (int i = 0; i < 7; i++)
+ {
+ Task task = getModel2Factory().createTask();
+ task.setDescription(Integer.toString(i));
+ container.getTasks().add(task);
+ }
+
+ tr1.commit();
+
+ sleep(500);
+
+ final CDOTransaction tr2 = session.openTransaction();
+
+ // Adds a conflict resolver.
+ tr2.options().addConflictResolver(new AbstractObjectConflictResolver2()
+ {
+ @Override
+ protected void resolveConflict(CDOObject conflict, CDORevision oldRevision, CDORevisionDelta localDelta,
+ CDORevisionDelta remoteDelta, List<CDORevisionDelta> deltas)
+ {
+ rollbackObject(conflict);
+
+ // Adjusts the local delta
+ CDOListFeatureDelta list = (CDOListFeatureDelta)localDelta.getFeatureDeltas().get(0);
+ CDORemoveFeatureDelta remove = (CDORemoveFeatureDelta)list.getListChanges().get(0);
+ ((WithIndex)remove).adjustAfterRemoval(0);
+
+ changeObject(conflict, localDelta);
+
+ // Adjusts the "notifications"
+ CDORevisionDelta delta = deltas.get(0);
+ list = (CDOListFeatureDelta)delta.getFeatureDeltas().get(0);
+ CDOMoveFeatureDelta move = (CDOMoveFeatureDelta)list.getListChanges().get(0);
+ ((WithIndex)move).adjustAfterRemoval(0);
+ }
+ });
+
+ TaskContainer otherContainer = tr2.getObject(container);
+ assertNotNull(otherContainer);
+
+ //
+ TestAdapter adapter = new TestAdapter();
+ otherContainer.eAdapters().add(adapter);
+
+ // Move in transaction 1.
+ container.getTasks().move(6, 0);
+
+ // Remove in transaction 2.
+ otherContainer.getTasks().remove(2);
+
+ tr1.commit();
+
+ sleep(500);
+
+ assertEquals(2, adapter.getNotifications().length);
+ assertEquals(Notification.REMOVE, adapter.getNotifications()[0].getEventType());
+ assertEquals(Notification.MOVE, adapter.getNotifications()[1].getEventType());
+ assertEquals(5, adapter.getNotifications()[1].getPosition());
+
+ tr2.commit();
+
+ sleep(500);
+
+ // At this point, both transactions must have an similar list.
+ assertEquals(container.getTasks().size(), otherContainer.getTasks().size());
+
+ Iterator<Task> i1 = container.getTasks().iterator();
+ Iterator<Task> i2 = otherContainer.getTasks().iterator();
+ while (i1.hasNext())
+ {
+ Task task1 = i1.next();
+ Task task2 = i2.next();
+ assertEquals(task1.getDescription(), task2.getDescription());
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_324544_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_324544_Test.java
new file mode 100644
index 0000000..07bb6f0
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_324544_Test.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.model1.Category;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CommitException;
+
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+
+import org.junit.Test;
+
+/**
+ * @author Eike Stepper
+ */
+public class Bugzilla_324544_Test extends AbstractCDOTest
+{
+
+ @Test
+ public void testCommitRefresh() throws CommitException
+ {
+ // user 1
+ CDOSession s1 = openSession();
+ CDOTransaction t1 = s1.openTransaction();
+ CDOResource r1 = t1.createResource("test");
+ Category c1 = getModel1Factory().createCategory();
+ r1.getContents().add(c1);
+ t1.commit();
+ c1.getProducts().add(getModel1Factory().createProduct1());
+
+ // user 2
+ CDOSession s2 = openSession();
+ s2.options().setPassiveUpdateEnabled(false);
+ CDOTransaction t2 = s2.openTransaction();
+ CDOResource r2 = t2.getResource("test");
+ Category c2 = (Category)r2.getContents().get(0);
+ c2.getProducts().add(getModel1Factory().createProduct1());
+ c2.eAdapters().add(new AdapterImpl());
+
+ // user 1
+ t1.commit();
+ // user2
+ s2.refresh();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java
index 17562c4..d907589 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java
@@ -490,7 +490,8 @@ public class CDOPushTransaction extends Notifier implements CDOTransaction
return delegate.queryXRefs(targetObjects, sourceReferences);
}
- public CloseableIterator<CDOObjectReference> queryXRefsAsync(Set<CDOObject> targetObjects, EReference... sourceReferences)
+ public CloseableIterator<CDOObjectReference> queryXRefsAsync(Set<CDOObject> targetObjects,
+ EReference... sourceReferences)
{
return delegate.queryXRefsAsync(targetObjects, sourceReferences);
}
@@ -510,6 +511,7 @@ public class CDOPushTransaction extends Notifier implements CDOTransaction
delegate.removeTransactionHandler(handler);
}
+ @Deprecated
public void resolveConflicts(CDOConflictResolver... resolver)
{
delegate.resolveConflicts(resolver);
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOTransaction.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOTransaction.java
index 70c2bf3..a532eb8 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOTransaction.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOTransaction.java
@@ -59,6 +59,7 @@ public interface CDOTransaction extends CDOView, CDOUserTransaction
public Set<CDOObject> getConflicts();
+ @Deprecated
public void resolveConflicts(CDOConflictResolver... resolver);
/**
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDONotificationBuilder.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDONotificationBuilder.java
index 34f3e64..9b36265 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDONotificationBuilder.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDONotificationBuilder.java
@@ -13,21 +13,17 @@ package org.eclipse.emf.internal.cdo;
import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
-import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDOFeatureDelta.WithIndex;
+import org.eclipse.emf.cdo.internal.common.revision.delta.CDOMoveFeatureDeltaImpl;
+import org.eclipse.emf.cdo.spi.common.revision.CDOFeatureDeltaVisitorImpl;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.emf.common.notify.Notification;
@@ -36,7 +32,6 @@ import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.InternalEObject;
-import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
@@ -45,7 +40,7 @@ import java.util.Set;
* @author Simon McDuff
* @since 2.0
*/
-public class CDONotificationBuilder implements CDOFeatureDeltaVisitor
+public class CDONotificationBuilder extends CDOFeatureDeltaVisitorImpl
{
private CDOView view;
@@ -55,18 +50,10 @@ public class CDONotificationBuilder implements CDOFeatureDeltaVisitor
private CDODeltaNotificationImpl notification;
- private InternalCDORevision revision;
-
- private boolean revisionLookedUp;
-
private Set<CDOObject> detachedObjects;
private InternalCDORevision oldRevision;
- private CDOListFeatureDelta patchedListDelta;
-
- private CDOListFeatureDelta unpatchedListDelta;
-
/**
* @since 3.0
*/
@@ -90,10 +77,6 @@ public class CDONotificationBuilder implements CDOFeatureDeltaVisitor
CDORevisionDelta revisionDelta, Set<CDOObject> detachedObjects)
{
notification = null;
- revision = null;
- revisionLookedUp = false;
- patchedListDelta = null;
- unpatchedListDelta = null;
this.object = object;
this.revisionDelta = revisionDelta;
@@ -103,15 +86,29 @@ public class CDONotificationBuilder implements CDOFeatureDeltaVisitor
return notification;
}
+ @Override
public void visit(CDOMoveFeatureDelta delta)
{
EStructuralFeature feature = delta.getFeature();
int oldPosition = delta.getOldPosition();
int newPosition = delta.getNewPosition();
+
+ Object oldValue = ((CDOMoveFeatureDeltaImpl)delta).getValue();
+ if (oldValue instanceof CDOID)
+ {
+ CDOID oldID = (CDOID)oldValue;
+ CDOObject object = findObjectByID(oldID);
+ if (object != null)
+ {
+ oldValue = object;
+ }
+ }
+
add(new CDODeltaNotificationImpl(object, Notification.MOVE, getEFeatureID(feature), Integer.valueOf(oldPosition),
- getOldValue(feature), newPosition));
+ oldValue, newPosition));
}
+ @Override
public void visit(CDOAddFeatureDelta delta)
{
EStructuralFeature feature = delta.getFeature();
@@ -119,22 +116,13 @@ public class CDONotificationBuilder implements CDOFeatureDeltaVisitor
delta.getValue(), delta.getIndex()));
}
+ @Override
public void visit(CDORemoveFeatureDelta delta)
{
EStructuralFeature feature = delta.getFeature();
int index = delta.getIndex();
- if (!revisionLookedUp)
- {
- InternalCDORevisionManager revisionManager = (InternalCDORevisionManager)view.getSession().getRevisionManager();
- revision = revisionManager.getRevisionByVersion(revisionDelta.getID(), revisionDelta, CDORevision.UNCHUNKED,
- false);
- }
- // Use patched index to retrieve object
- int unpatchedIndex = unpatchedListDelta.getListChanges().indexOf(delta);
- CDORemoveFeatureDelta unpatchedDelta = (CDORemoveFeatureDelta)patchedListDelta.getListChanges().get(unpatchedIndex);
- int patchedIndex = unpatchedDelta.getIndex();
- Object oldValue = revision == null ? null : revision.get(feature, patchedIndex);
+ Object oldValue = delta.getValue();
if (oldValue instanceof CDOID)
{
CDOID oldID = (CDOID)oldValue;
@@ -148,6 +136,7 @@ public class CDONotificationBuilder implements CDOFeatureDeltaVisitor
add(new CDODeltaNotificationImpl(object, Notification.REMOVE, getEFeatureID(feature), oldValue, null, index));
}
+ @Override
public void visit(CDOSetFeatureDelta delta)
{
EStructuralFeature feature = delta.getFeature();
@@ -165,6 +154,7 @@ public class CDONotificationBuilder implements CDOFeatureDeltaVisitor
add(new CDODeltaNotificationImpl(object, Notification.SET, getEFeatureID(feature), oldValue, delta.getValue()));
}
+ @Override
public void visit(CDOUnsetFeatureDelta delta)
{
EStructuralFeature feature = delta.getFeature();
@@ -182,83 +172,7 @@ public class CDONotificationBuilder implements CDOFeatureDeltaVisitor
add(new CDODeltaNotificationImpl(object, Notification.UNSET, getEFeatureID(feature), oldValue, null));
}
- public void visit(CDOListFeatureDelta deltas)
- {
- unpatchedListDelta = deltas;
- patchedListDelta = (CDOListFeatureDelta)deltas.copy();
- patchIndices(patchedListDelta);
- for (CDOFeatureDelta delta : deltas.getListChanges())
- {
- delta.accept(this);
- }
- }
-
- private void patchIndices(CDOListFeatureDelta deltas)
- {
- List<CDOFeatureDelta> restDeltas = new ArrayList<CDOFeatureDelta>();
- restDeltas.addAll(deltas.getListChanges());
- for (CDOFeatureDelta delta : deltas.getListChanges())
- {
- restDeltas.remove(delta);
- if (delta instanceof CDOAddFeatureDelta)
- {
- CDOAddFeatureDelta addDelta = (CDOAddFeatureDelta)delta;
- for (CDOFeatureDelta restDelta : restDeltas)
- {
- if (restDelta instanceof CDOClearFeatureDelta)
- {
- break;
- }
-
- if (restDelta instanceof WithIndex)
- {
- WithIndex withIndex = (WithIndex)restDelta;
- withIndex.adjustAfterRemoval(addDelta.getIndex());
- }
- }
- }
- else if (delta instanceof CDORemoveFeatureDelta)
- {
- CDORemoveFeatureDelta removeDelta = (CDORemoveFeatureDelta)delta;
- for (CDOFeatureDelta restDelta : restDeltas)
- {
- if (restDelta instanceof CDOClearFeatureDelta)
- {
- break;
- }
-
- if (restDelta instanceof WithIndex)
- {
- WithIndex withIndex = (WithIndex)restDelta;
- withIndex.adjustAfterAddition(removeDelta.getIndex());
- }
- }
- }
- else if (delta instanceof CDOClearFeatureDelta)
- {
- // Do nothing
- }
- else if (delta instanceof CDOMoveFeatureDelta)
- {
- CDOMoveFeatureDelta moveDelta = (CDOMoveFeatureDelta)delta;
- for (CDOFeatureDelta restDelta : restDeltas)
- {
- if (restDelta instanceof CDOClearFeatureDelta)
- {
- break;
- }
-
- if (restDelta instanceof WithIndex)
- {
- WithIndex withIndex = (WithIndex)restDelta;
- withIndex.adjustAfterAddition(moveDelta.getOldPosition());
- withIndex.adjustAfterRemoval(moveDelta.getNewPosition());
- }
- }
- }
- }
- }
-
+ @Override
public void visit(CDOClearFeatureDelta delta)
{
EStructuralFeature feature = delta.getFeature();
@@ -315,6 +229,7 @@ public class CDONotificationBuilder implements CDOFeatureDeltaVisitor
return null;
}
+ @Override
public void visit(CDOContainerFeatureDelta delta)
{
Object oldValue = null;
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStore.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStore.java
index 106cddc..dc6b9ea 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStore.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStore.java
@@ -412,6 +412,8 @@ public final class CDOStore implements EStore
TRACER.format("remove({0}, {1}, {2})", cdoObject, feature, index); //$NON-NLS-1$
}
+ Object oldValue = null;
+
// Bugzilla 293283 / 314387
if (feature.isMany())
{
@@ -427,7 +429,7 @@ public final class CDOStore implements EStore
CDOFeatureDelta delta = new CDORemoveFeatureDeltaImpl(feature, index);
InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
- Object oldValue = revision.remove(feature, index);
+ oldValue = revision.remove(feature, index);
return convertToEMF(eObject, revision, feature, index, oldValue);
}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
index e0bb42a..427685b 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
@@ -35,10 +35,19 @@ import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
import org.eclipse.emf.cdo.common.protocol.CDOAuthenticator;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
+import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
+import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
import org.eclipse.emf.cdo.common.util.CDOException;
import org.eclipse.emf.cdo.common.util.RepositoryStateChangedEvent;
import org.eclipse.emf.cdo.common.util.RepositoryTypeChangedEvent;
+import org.eclipse.emf.cdo.internal.common.revision.delta.CDOMoveFeatureDeltaImpl;
+import org.eclipse.emf.cdo.internal.common.revision.delta.CDOSingleValueFeatureDeltaImpl;
import org.eclipse.emf.cdo.session.CDOCollectionLoadingPolicy;
import org.eclipse.emf.cdo.session.CDORepositoryInfo;
import org.eclipse.emf.cdo.session.CDOSession;
@@ -51,6 +60,7 @@ import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
import org.eclipse.emf.cdo.spi.common.commit.CDORevisionAvailabilityInfo;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+import org.eclipse.emf.cdo.spi.common.revision.CDOFeatureDeltaVisitorImpl;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
@@ -88,6 +98,7 @@ import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.net4j.util.options.IOptionsContainer;
import org.eclipse.net4j.util.options.OptionsEvent;
+import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.ResourceSet;
@@ -737,6 +748,66 @@ public abstract class CDOSessionImpl extends Container<CDOView> implements Inter
// Apply deltas and cache the resulting new revisions, if possible...
for (CDORevisionKey key : commitInfo.getChangedObjects())
{
+ // Add old values to revision deltas.
+ if (key instanceof CDORevisionDelta)
+ {
+ final CDORevisionDelta revisionDelta = (CDORevisionDelta)key;
+ final CDORevision oldRevision = revisionManager.getRevisionByVersion(revisionDelta.getID(), revisionDelta,
+ CDORevision.UNCHUNKED, false);
+
+ if (oldRevision != null)
+ {
+ CDOFeatureDeltaVisitor visitor = new CDOFeatureDeltaVisitorImpl()
+ {
+ private List<Object> workList;
+
+ @Override
+ public void visit(CDOAddFeatureDelta delta)
+ {
+ workList.add(delta.getIndex(), delta.getValue());
+ }
+
+ @Override
+ public void visit(CDOClearFeatureDelta delta)
+ {
+ workList.clear();
+ }
+
+ @Override
+ public void visit(CDOListFeatureDelta deltas)
+ {
+ @SuppressWarnings("unchecked")
+ List<Object> list = (List<Object>)((InternalCDORevision)oldRevision).getValue(deltas.getFeature());
+ if (list != null)
+ {
+ workList = new ArrayList<Object>(list);
+ super.visit(deltas);
+ }
+ }
+
+ @Override
+ public void visit(CDOMoveFeatureDelta delta)
+ {
+ Object value = workList.get(delta.getOldPosition());
+ ((CDOMoveFeatureDeltaImpl)delta).setValue(value);
+ ECollections.move(workList, delta.getNewPosition(), delta.getOldPosition());
+ }
+
+ @Override
+ public void visit(CDORemoveFeatureDelta delta)
+ {
+ Object oldValue = workList.remove(delta.getIndex());
+ ((CDOSingleValueFeatureDeltaImpl)delta).setValue(oldValue);
+ }
+ };
+
+ for (CDOFeatureDelta featureDelta : revisionDelta.getFeatureDeltas())
+ {
+ featureDelta.accept(visitor);
+ }
+ }
+ }
+
CDOID id = key.getID();
Pair<InternalCDORevision, InternalCDORevision> pair = createNewRevision(key, commitInfo);
if (pair != null)
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/AbstractObjectConflictResolver2.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/AbstractObjectConflictResolver2.java
new file mode 100644
index 0000000..1f8ee20
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/AbstractObjectConflictResolver2.java
@@ -0,0 +1,243 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Eike Stepper - initial API and implementation
+ **************************************************************************/
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.CDOState;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+import org.eclipse.emf.cdo.common.util.CDOException;
+import org.eclipse.emf.cdo.spi.common.revision.CDORevisionMerger;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+
+import org.eclipse.emf.internal.cdo.CDOObjectMerger;
+import org.eclipse.emf.internal.cdo.CDOStateMachine;
+import org.eclipse.emf.internal.cdo.messages.Messages;
+
+import org.eclipse.net4j.util.collection.Pair;
+
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.spi.cdo.InternalCDOObject;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * @author Eike Stepper
+ * @since 2.0
+ */
+public abstract class AbstractObjectConflictResolver2 implements CDOConflictResolver2
+{
+ private CDOTransaction transaction;
+
+ public AbstractObjectConflictResolver2()
+ {
+ }
+
+ public CDOTransaction getTransaction()
+ {
+ return transaction;
+ }
+
+ public void setTransaction(CDOTransaction transaction)
+ {
+ if (this.transaction != transaction)
+ {
+ if (this.transaction != null)
+ {
+ unhookTransaction(this.transaction);
+ }
+
+ this.transaction = transaction;
+
+ if (this.transaction != null)
+ {
+ hookTransaction(this.transaction);
+ }
+ }
+ }
+
+ public void resolveConflicts(Set<CDOObject> conflicts)
+ {
+ // Do nothing
+ }
+
+ /**
+ * Resolves the conflicts in the current transaction. Depending on the decision taken to resolve the conflicts, it may
+ * be necessary to adjust the notifications that will be sent to the adapters in the current transaction. This can be
+ * achieved by adjusting the {@link CDORevisionDelta} in <code>deltas</code>.
+ *
+ * @param deltas
+ */
+ public void resolveConflicts(Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts,
+ List<CDORevisionDelta> deltas)
+ {
+ Map<CDOID, CDORevisionDelta> localDeltas = transaction.getRevisionDeltas();
+ for (Entry<CDOObject, Pair<CDORevision, CDORevisionDelta>> entry : conflicts.entrySet())
+ {
+ CDOObject conflict = entry.getKey();
+ CDORevision oldRevision = entry.getValue().getElement1();
+ CDORevisionDelta remoteDelta = entry.getValue().getElement2();
+ CDORevisionDelta localDelta = localDeltas.get(conflict.cdoID());
+ resolveConflict(conflict, oldRevision, localDelta, remoteDelta, deltas);
+ }
+ }
+
+ /**
+ * Resolves the conflict of a single object in the current transaction. Depending on the decision taken to resolve the
+ * conflict, it may be necessary to adjust the notification that will be sent to the adapters in the current
+ * transaction. This can be achieved by adjusting the {@link CDORevisionDelta} in <code>deltas</code>.
+ *
+ * @param deltas
+ */
+ protected abstract void resolveConflict(CDOObject conflict, CDORevision oldRevision, CDORevisionDelta localDelta,
+ CDORevisionDelta remoteDelta, List<CDORevisionDelta> deltas);
+
+ protected void hookTransaction(CDOTransaction transaction)
+ {
+ }
+
+ protected void unhookTransaction(CDOTransaction transaction)
+ {
+ }
+
+ public static void rollbackObject(CDOObject object)
+ {
+ CDOStateMachine.INSTANCE.rollback((InternalCDOObject)object);
+ }
+
+ public static void readObject(CDOObject object)
+ {
+ CDOStateMachine.INSTANCE.read((InternalCDOObject)object);
+ }
+
+ /**
+ * TODO See {@link CDOObjectMerger}!!!
+ */
+ public static void changeObject(CDOObject object, CDORevisionDelta revisionDelta)
+ {
+ readObject(object);
+
+ InternalCDORevision revision = (InternalCDORevision)object.cdoRevision().copy();
+ ((InternalCDORevisionDelta)revisionDelta).setVersion(revision.getVersion());
+
+ CDORevisionMerger merger = new CDORevisionMerger();
+ merger.merge(revision, revisionDelta);
+ ((InternalCDOObject)object).cdoInternalSetRevision(revision);
+ ((InternalCDOObject)object).cdoInternalSetState(CDOState.DIRTY);
+ ((InternalCDOObject)object).cdoInternalPostLoad();
+ }
+
+ /**
+ * A conflict resolver implementation that takes all the new remote state of the conflicting objects and then applies
+ * the locally existing changes of the current transaction.
+ *
+ * @author Eike Stepper
+ * @since 2.0
+ */
+ public static class TakeRemoteChangesThenApplyLocalChanges extends AbstractObjectConflictResolver2
+ {
+ public TakeRemoteChangesThenApplyLocalChanges()
+ {
+ }
+
+ @Override
+ protected void resolveConflict(CDOObject conflict, CDORevision oldRevision, CDORevisionDelta localDelta,
+ CDORevisionDelta remoteDelta, List<CDORevisionDelta> deltas)
+ {
+ rollbackObject(conflict);
+ changeObject(conflict, localDelta);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 2.0
+ */
+ public static abstract class ThreeWayMerge extends AbstractObjectConflictResolver2
+ {
+ @Override
+ protected void resolveConflict(CDOObject conflict, CDORevision oldRevision, CDORevisionDelta localDelta,
+ CDORevisionDelta remoteDelta, List<CDORevisionDelta> deltas)
+ {
+ resolveConflict(conflict, localDelta, Collections.singletonList(remoteDelta));
+ }
+
+ protected abstract void resolveConflict(CDOObject conflict, CDORevisionDelta localDelta,
+ List<CDORevisionDelta> remoteDeltas);
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 3.0
+ */
+ public static class MergeLocalChangesPerFeature extends ThreeWayMerge
+ {
+ public MergeLocalChangesPerFeature()
+ {
+ }
+
+ @Override
+ protected void resolveConflict(CDOObject conflict, CDORevisionDelta localDelta, List<CDORevisionDelta> remoteDeltas)
+ {
+ if (hasFeatureConflicts(localDelta, remoteDeltas))
+ {
+ // TODO localDelta may be corrupt already and the transaction will not be able to restore it!!!
+ throw new CDOException(Messages.getString("AbstractObjectConflictResolver.0")); //$NON-NLS-1$
+ }
+
+ rollbackObject(conflict);
+
+ // Add remote deltas to local delta
+ for (CDORevisionDelta remoteDelta : remoteDeltas)
+ {
+ for (CDOFeatureDelta remoteFeatureDelta : remoteDelta.getFeatureDeltas())
+ {
+ // TODO Add public API for this:
+ ((InternalCDORevisionDelta)localDelta).addFeatureDelta(remoteFeatureDelta);
+ }
+ }
+
+ changeObject(conflict, localDelta);
+ }
+
+ protected boolean hasFeatureConflicts(CDORevisionDelta localDelta, List<CDORevisionDelta> remoteDeltas)
+ {
+ Set<EStructuralFeature> features = new HashSet<EStructuralFeature>();
+ for (CDOFeatureDelta localFeatureDelta : localDelta.getFeatureDeltas())
+ {
+ features.add(localFeatureDelta.getFeature());
+ }
+
+ for (CDORevisionDelta remoteDelta : remoteDeltas)
+ {
+ for (CDOFeatureDelta remoteFeatureDelta : remoteDelta.getFeatureDeltas())
+ {
+ EStructuralFeature feature = remoteFeatureDelta.getFeature();
+ if (features.contains(feature))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOConflictResolver2.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOConflictResolver2.java
new file mode 100644
index 0000000..5cae47a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOConflictResolver2.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) 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:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+import org.eclipse.emf.cdo.transaction.CDOConflictResolver;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+
+import org.eclipse.net4j.util.collection.Pair;
+
+import org.eclipse.emf.spi.cdo.AbstractObjectConflictResolver;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A strategy used to customize the default conflict resolution behaviour of {@link CDOTransaction transactions}.
+ *
+ * @see CDOTransaction.Options#addConflictResolver(CDOConflictResolver)
+ * @author Eike Stepper
+ */
+public interface CDOConflictResolver2 extends CDOConflictResolver
+{
+ /**
+ * Resolves conflicts after remote invalidations arrived for objects that are locally dirty or detached.
+ * <p>
+ * Depending on the decisions taken to resolve the conflict, it may be necessary to adjust the notifications that will
+ * be sent to the adapters in the current transaction. This can be achieved by adjusting the {@link CDORevisionDelta}
+ * in <code>deltas</code>.
+ * <p>
+ * The implementor might want to use/extend {@link AbstractObjectConflictResolver}.
+ */
+ public void resolveConflicts(Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts,
+ List<CDORevisionDelta> deltas);
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
index 5c82bd2..d7d2250 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
@@ -97,6 +97,7 @@ import org.eclipse.emf.internal.cdo.view.CDOViewImpl;
import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.collection.FastList;
+import org.eclipse.net4j.util.collection.Pair;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.io.ExtendedDataInputStream;
import org.eclipse.net4j.util.io.ExtendedDataOutputStream;
@@ -638,6 +639,75 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa
conflict -= resolved;
}
+ public void handleConflicts(Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts,
+ List<CDORevisionDelta> deltas)
+ {
+ handleConflicts(conflicts, options().getConflictResolvers(), deltas);
+ }
+
+ private void handleConflicts(Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts,
+ CDOConflictResolver[] resolvers, List<CDORevisionDelta> deltas)
+ {
+ if (resolvers.length == 0)
+ {
+ return;
+ }
+
+ // Remember original state to be able to restore it after an exception
+ List<CDOState> states = new ArrayList<CDOState>(conflicts.size());
+ List<CDORevision> revisions = new ArrayList<CDORevision>(conflicts.size());
+ for (CDOObject conflict : conflicts.keySet())
+ {
+ states.add(conflict.cdoState());
+ revisions.add(conflict.cdoRevision());
+ }
+
+ int resolved = 0;
+
+ try
+ {
+ Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> remaining = new HashMap<CDOObject, Pair<CDORevision, CDORevisionDelta>>(
+ conflicts);
+ for (CDOConflictResolver resolver : resolvers)
+ {
+ if (resolver instanceof CDOConflictResolver2)
+ {
+ CDOConflictResolver2 resolver2 = (CDOConflictResolver2)resolver;
+ resolver2.resolveConflicts(Collections.unmodifiableMap(remaining), deltas);
+ }
+ else
+ {
+ resolver.resolveConflicts(Collections.unmodifiableSet(remaining.keySet()));
+ }
+
+ for (Iterator<CDOObject> it = remaining.keySet().iterator(); it.hasNext();)
+ {
+ CDOObject object = it.next();
+ if (!object.cdoConflict())
+ {
+ ++resolved;
+ it.remove();
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ // Restore original state
+ Iterator<CDOState> state = states.iterator();
+ Iterator<CDORevision> revision = revisions.iterator();
+ for (CDOObject object : conflicts.keySet())
+ {
+ ((InternalCDOObject)object).cdoInternalSetState(state.next());
+ ((InternalCDOObject)object).cdoInternalSetRevision(revision.next());
+ }
+
+ throw WrappedException.wrap(ex);
+ }
+
+ conflict -= resolved;
+ }
+
public CDOIDTemp getNextTemporaryID()
{
return CDOIDUtil.createTempObject(lastTemporaryID.incrementAndGet());
@@ -1814,9 +1884,9 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa
* @since 3.0
*/
@Override
- protected Set<CDOObject> invalidate(long lastUpdateTime, List<CDORevisionKey> allChangedObjects,
- List<CDOIDAndVersion> allDetachedObjects, List<CDORevisionDelta> deltas, Set<InternalCDOObject> changedObjects,
- Set<CDOObject> detachedObjects)
+ protected Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> invalidate(long lastUpdateTime,
+ List<CDORevisionKey> allChangedObjects, List<CDOIDAndVersion> allDetachedObjects, List<CDORevisionDelta> deltas,
+ Set<InternalCDOObject> changedObjects, Set<CDOObject> detachedObjects)
{
if (!allDetachedObjects.isEmpty())
{
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java
index 2e1e9bb..8d4a001 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java
@@ -37,6 +37,8 @@ import org.eclipse.emf.cdo.eresource.CDOResourceFolder;
import org.eclipse.emf.cdo.eresource.CDOResourceNode;
import org.eclipse.emf.cdo.eresource.EresourcePackage;
import org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl;
+import org.eclipse.emf.cdo.internal.common.revision.delta.CDODetachedRevisionDeltaImpl;
+import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl;
import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
@@ -72,6 +74,7 @@ import org.eclipse.emf.internal.cdo.CDOURIHandler;
import org.eclipse.emf.internal.cdo.bundle.OM;
import org.eclipse.emf.internal.cdo.messages.Messages;
import org.eclipse.emf.internal.cdo.query.CDOQueryImpl;
+import org.eclipse.emf.internal.cdo.transaction.CDOTransactionImpl;
import org.eclipse.emf.internal.cdo.util.FSMUtil;
import org.eclipse.net4j.util.ImplementationError;
@@ -81,6 +84,7 @@ import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.collection.CloseableIterator;
import org.eclipse.net4j.util.collection.FastList;
import org.eclipse.net4j.util.collection.HashBag;
+import org.eclipse.net4j.util.collection.Pair;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.event.Notifier;
@@ -1454,7 +1458,7 @@ public class CDOViewImpl extends Lifecycle implements InternalCDOView
public void invalidate(long lastUpdateTime, List<CDORevisionKey> allChangedObjects,
List<CDOIDAndVersion> allDetachedObjects, Map<CDOID, InternalCDORevision> oldRevisions)
{
- Set<CDOObject> conflicts = null;
+ Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts = null;
List<CDORevisionDelta> deltas = new ArrayList<CDORevisionDelta>();
Set<InternalCDOObject> changedObjects = new HashSet<InternalCDOObject>();
Set<CDOObject> detachedObjects = new HashSet<CDOObject>();
@@ -1474,32 +1478,50 @@ public class CDOViewImpl extends Lifecycle implements InternalCDOView
fireInvalidationEvent(lastUpdateTime, Collections.unmodifiableSet(changedObjects),
Collections.unmodifiableSet(detachedObjects));
- if (!deltas.isEmpty() || !detachedObjects.isEmpty())
+ // First handle the conflicts if any.
+ if (conflicts != null)
{
- sendDeltaNotifications(deltas, detachedObjects, oldRevisions);
+ if (this instanceof CDOTransactionImpl)
+ {
+ CDOTransactionImpl transaction = (CDOTransactionImpl)this;
+
+ // Give the deltas to the conflict resolvers. Thus they can adjust them so that sendDeltaNotifications can
+ // generate correct notifications.
+ transaction.handleConflicts(conflicts, deltas);
+ }
+ else
+ {
+ InternalCDOTransaction transaction = (InternalCDOTransaction)this;
+ transaction.handleConflicts(conflicts.keySet());
+ }
}
- if (conflicts != null)
+ // Then send the notifications. The deltas could have been modified by the conflict resolvers.
+ if (!deltas.isEmpty() || !detachedObjects.isEmpty())
{
- InternalCDOTransaction transaction = (InternalCDOTransaction)this;
- transaction.handleConflicts(conflicts);
+ sendDeltaNotifications(deltas, detachedObjects, oldRevisions);
}
fireAdaptersNotifiedEvent(lastUpdateTime);
setLastUpdateTime(lastUpdateTime);
}
- protected Set<CDOObject> invalidate(long lastUpdateTime, List<CDORevisionKey> allChangedObjects,
- List<CDOIDAndVersion> allDetachedObjects, List<CDORevisionDelta> deltas, Set<InternalCDOObject> changedObjects,
- Set<CDOObject> detachedObjects)
+ protected Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> invalidate(long lastUpdateTime,
+ List<CDORevisionKey> allChangedObjects, List<CDOIDAndVersion> allDetachedObjects, List<CDORevisionDelta> deltas,
+ Set<InternalCDOObject> changedObjects, Set<CDOObject> detachedObjects)
{
- Set<CDOObject> conflicts = null;
+ Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts = null;
for (CDORevisionKey key : allChangedObjects)
{
CDORevisionDelta delta = null;
if (key instanceof CDORevisionDelta)
{
delta = (CDORevisionDelta)key;
+ // Clone the revision delta if we are a transaction. Thus a conflict resolver will be allowed to modify them.
+ if (this instanceof CDOTransaction)
+ {
+ delta = new CDORevisionDeltaImpl(delta, true);
+ }
deltas.add(delta);
}
@@ -1512,6 +1534,8 @@ public class CDOViewImpl extends Lifecycle implements InternalCDOView
if (changedObject != null)
{
+ Pair<CDORevision, CDORevisionDelta> oldInfo = new Pair<CDORevision, CDORevisionDelta>(
+ changedObject.cdoRevision(), delta);
// if (!isLocked(changedObject))
{
CDOStateMachine.INSTANCE.invalidate(changedObject, key, lastUpdateTime);
@@ -1522,10 +1546,10 @@ public class CDOViewImpl extends Lifecycle implements InternalCDOView
{
if (conflicts == null)
{
- conflicts = new HashSet<CDOObject>();
+ conflicts = new HashMap<CDOObject, Pair<CDORevision, CDORevisionDelta>>();
}
- conflicts.add(changedObject);
+ conflicts.put(changedObject, oldInfo);
}
}
}
@@ -1535,6 +1559,8 @@ public class CDOViewImpl extends Lifecycle implements InternalCDOView
InternalCDOObject detachedObject = removeObject(key.getID());
if (detachedObject != null)
{
+ Pair<CDORevision, CDORevisionDelta> oldInfo = new Pair<CDORevision, CDORevisionDelta>(
+ detachedObject.cdoRevision(), CDODetachedRevisionDeltaImpl.DETACHED);
// if (!isLocked(detachedObject))
{
CDOStateMachine.INSTANCE.detachRemote(detachedObject);
@@ -1545,10 +1571,10 @@ public class CDOViewImpl extends Lifecycle implements InternalCDOView
{
if (conflicts == null)
{
- conflicts = new HashSet<CDOObject>();
+ conflicts = new HashMap<CDOObject, Pair<CDORevision, CDORevisionDelta>>();
}
- conflicts.add(detachedObject);
+ conflicts.put(detachedObject, oldInfo);
}
}
}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java
index 22f9b98..b3e20c6 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/InternalCDOTransaction.java
@@ -88,8 +88,8 @@ public interface InternalCDOTransaction extends CDOTransaction, InternalCDOUserT
/**
* @since 3.0
*/
- public CDOChangeSetData applyChangeSetData(CDOChangeSetData changeSetData,
- CDORevisionAvailabilityInfo ancestorInfo, CDORevisionAvailabilityInfo targetInfo, CDORevisionAvailabilityInfo sourceInfo);
+ public CDOChangeSetData applyChangeSetData(CDOChangeSetData changeSetData, CDORevisionAvailabilityInfo ancestorInfo,
+ CDORevisionAvailabilityInfo targetInfo, CDORevisionAvailabilityInfo sourceInfo);
/**
* @since 3.0