Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2010-06-14 11:27:09 +0000
committerEike Stepper2010-06-14 11:27:09 +0000
commit6ec4b59eb56ff17361d5d376110a707aed559118 (patch)
treed4572f45e0ce1bb76b4b61eabccfd6d34614786a
parent45e8fd8adc183a5ff8cd9e92cdea7512468eb2e7 (diff)
downloadcdo-6ec4b59eb56ff17361d5d376110a707aed559118.tar.gz
cdo-6ec4b59eb56ff17361d5d376110a707aed559118.tar.xz
cdo-6ec4b59eb56ff17361d5d376110a707aed559118.zip
[310574] CDOAddFeatureDelta with null value
https://bugs.eclipse.org/bugs/show_bug.cgi?id=310574
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOListFeatureDeltaImpl.java154
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_310574_Test.java1164
3 files changed, 1313 insertions, 7 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOListFeatureDeltaImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOListFeatureDeltaImpl.java
index 78b55f31de..122ae5a1a6 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOListFeatureDeltaImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/delta/CDOListFeatureDeltaImpl.java
@@ -6,8 +6,9 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Simon McDuff - initial API and implementation
- * Eike Stepper - maintenance
+ * Simon McDuff - initial API and implementation
+ * Eike Stepper - maintenance
+ * Cyril Jaquier - Bug 310574 (with the help of Pascal Lehmann)
*/
package org.eclipse.emf.cdo.internal.common.revision.delta;
@@ -15,9 +16,11 @@ import org.eclipse.emf.cdo.common.protocol.CDODataInput;
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.revision.CDOReferenceAdjuster;
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.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.net4j.util.ObjectUtil;
@@ -34,6 +37,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
/**
@@ -204,7 +208,7 @@ public class CDOListFeatureDeltaImpl extends CDOFeatureDeltaImpl implements CDOL
}
}
- private void cleanupWithNewDelta(CDOFeatureDelta featureDelta)
+ private boolean cleanupWithNewDelta(CDOFeatureDelta featureDelta)
{
EStructuralFeature feature = getFeature();
if ((feature instanceof EReference || FeatureMapUtil.isFeatureMap(feature))
@@ -218,8 +222,139 @@ public class CDOListFeatureDeltaImpl extends CDOFeatureDeltaImpl implements CDOL
int index = cachedIndices[i];
if (indexToRemove == index)
{
- cachedSources[i].clear();
- break;
+ // The previous implementation set the value of the feature delta to CDOID.NULL. Databinding and probably
+ // others don't really like it. We now remove the ADD (or SET which seems to appear in CDOListFeatureDelta
+ // during opposite adjustment!? Why???) and patch the other feature deltas.
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=310574
+
+ ListTargetAdding delta = cachedSources[i];
+
+ // We use a "floating" index which is the index (in the list) of the item to remove at the time when the
+ // object was still in the list. This index evolves with the feature deltas.
+ int floatingIndex = delta.getIndex();
+
+ // First updates cachedSources and cachedIndices using CDORemoveFeatureDelta.
+ ListIndexAffecting affecting = (ListIndexAffecting)featureDelta;
+ affecting.affectIndices(cachedSources, cachedIndices);
+
+ // Then adjusts the remaining feature deltas.
+ boolean skip = true;
+ ListIterator<CDOFeatureDelta> iterator = featureDeltas.listIterator();
+
+ while (iterator.hasNext())
+ {
+ CDOFeatureDelta fd = iterator.next();
+
+ // We only need to process feature deltas that come after the ADD (or SET) to be removed.
+ if (skip)
+ {
+ if (fd == delta)
+ {
+ // Found the ADD (or SET) feature delta that we need to remove. So remove it from the list and start
+ // processing the next feature deltas.
+ skip = false;
+ iterator.remove();
+ }
+ continue;
+ }
+
+ // SET
+ // Should we take care of it?
+
+ // ADD
+ if (fd instanceof CDOAddFeatureDelta)
+ {
+ // Increases the floating index if the ADD came in front of the item.
+ if (((CDOAddFeatureDelta)fd).getIndex() <= floatingIndex)
+ {
+ ++floatingIndex;
+ }
+ // Adjusts the feature delta too.
+ ((WithIndex)fd).adjustAfterRemoval(floatingIndex);
+ }
+
+ // REMOVE
+ else if (fd instanceof CDORemoveFeatureDelta)
+ {
+ int idx = floatingIndex;
+ // Decreases the floating index if the REMOVE came in front of the item.
+ if (((CDORemoveFeatureDelta)fd).getIndex() <= floatingIndex)
+ {
+ --floatingIndex;
+ }
+ // Adjusts the feature delta too.
+ ((WithIndex)fd).adjustAfterRemoval(idx);
+ }
+
+ // MOVE
+ else if (fd instanceof CDOMoveFeatureDelta)
+ {
+ // Remembers the positions before we patch them.
+ int from = ((CDOMoveFeatureDelta)fd).getOldPosition();
+ int to = ((CDOMoveFeatureDelta)fd).getNewPosition();
+
+ if (floatingIndex == from)
+ {
+ // We are moving the "to be deleted" item. So we update our floating index and remove the MOVE. It has
+ // no effect on the list.
+ floatingIndex = to;
+ iterator.remove();
+ }
+ else
+ {
+ // In the other cases, we need to patch the positions.
+
+ // If the old position is greater or equal to the current position of the item to be removed (remember,
+ // that's our floating index), decrease the position.
+ int patchedFrom = floatingIndex <= from ? from - 1 : from;
+
+ // The new position requires more care. We need to know the direction of the move (left-to-right or
+ // right-to-left).
+ int patchedTo;
+ if (from > to)
+ {
+ // left-to-right. Only decreases the position if it is strictly greater than the current item
+ // position.
+ patchedTo = floatingIndex < to ? to - 1 : to;
+ }
+ else
+ {
+ // right-to-left. Decreases the position if it is greater or equal than the current item position.
+ patchedTo = floatingIndex <= to ? to - 1 : to;
+ }
+
+ // We can now update our floating index. We use the original positions because the floating index
+ // represents the item "to be deleted" before it was actually removed.
+ if (from < floatingIndex && floatingIndex <= to)
+ {
+ --floatingIndex;
+ }
+ else if (to <= floatingIndex && floatingIndex < from)
+ {
+ ++floatingIndex;
+ }
+
+ // And finally adjust the feature delta.
+ if (patchedFrom == patchedTo)
+ {
+ // Source and destination are the same so just remove the feature delta.
+ iterator.remove();
+ }
+ else
+ {
+ // It is not possible to modify the positions of a CDOMoveFeatureDeltaImpl so we create a new instance
+ // that will replace the old one.
+ CDOMoveFeatureDelta move = new CDOMoveFeatureDeltaImpl(fd.getFeature(), patchedTo, patchedFrom);
+ iterator.set(move);
+ }
+
+ }
+ }
+
+ }
+
+ // We virtually "executed" the REMOVE so we do not add it to the feature deltas.
+ return false;
}
}
}
@@ -233,12 +368,17 @@ public class CDOListFeatureDeltaImpl extends CDOFeatureDeltaImpl implements CDOL
unprocessedFeatureDeltas.add(featureDelta);
}
+
+ return true;
}
public void add(CDOFeatureDelta featureDelta)
{
- cleanupWithNewDelta(featureDelta);
- featureDeltas.add(featureDelta);
+ // Only adds the feature delta to the list if required.
+ if (cleanupWithNewDelta(featureDelta))
+ {
+ featureDeltas.add(featureDelta);
+ }
}
public void apply(CDORevision revision)
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 897cc32770..a567850cef 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
@@ -72,6 +72,7 @@ import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_303807_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_306710_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_306998_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_308895_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_310574_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_314264_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_316145_Test;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest;
@@ -207,6 +208,7 @@ public abstract class AllConfigs extends ConfigTestSuite
testClasses.add(Bugzilla_306710_Test.class);
testClasses.add(Bugzilla_306998_Test.class);
testClasses.add(Bugzilla_308895_Test.class);
+ testClasses.add(Bugzilla_310574_Test.class);
// testClasses.add(Bugzilla_313326_Test.class);
testClasses.add(Bugzilla_314264_Test.class);
testClasses.add(Bugzilla_316145_Test.class);
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_310574_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_310574_Test.java
new file mode 100644
index 0000000000..aa96d41911
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_310574_Test.java
@@ -0,0 +1,1164 @@
+/**
+ * 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.server.IRepository.WriteAccessHandler;
+import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
+import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.model1.Customer;
+import org.eclipse.emf.cdo.tests.model1.Model1Package;
+import org.eclipse.emf.cdo.tests.model1.PurchaseOrder;
+import org.eclipse.emf.cdo.tests.model1.SalesOrder;
+import org.eclipse.emf.cdo.tests.model1.Supplier;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import org.eclipse.emf.common.util.EList;
+
+import java.util.Random;
+
+/**
+ * CDOAddFeatureDelta with null value.
+ * <p>
+ * See bug 310574
+ *
+ * @author Eike Stepper
+ */
+public class Bugzilla_310574_Test extends AbstractCDOTest
+{
+ @SuppressWarnings("unused")
+ private final WriteAccessHandler printHandler = new WriteAccessHandler()
+ {
+ public void handleTransactionBeforeCommitting(ITransaction transaction, CommitContext commitContext,
+ OMMonitor monitor) throws RuntimeException
+ {
+ InternalCDORevisionDelta[] deltas = commitContext.getDirtyObjectDeltas();
+ for (InternalCDORevisionDelta delta : deltas)
+ {
+ if (delta.getEClass() == Model1Package.Literals.CUSTOMER)
+ {
+ System.out.println(delta);
+ }
+ }
+ }
+
+ public void handleTransactionAfterCommitted(ITransaction transaction, CommitContext commitContext, OMMonitor monitor)
+ {
+ }
+ };
+
+ private SalesOrder[] createSalesOrders(int number)
+ {
+ SalesOrder orders[] = new SalesOrder[number];
+ for (int i = 0; i < number; i++)
+ {
+ orders[i] = getModel1Factory().createSalesOrder();
+ orders[i].setId(i);
+ }
+ return orders;
+ }
+
+ @Override
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ // Adds our handler.
+ // getRepository().addHandler(printHandler);
+ }
+
+ public void testAddAndModifyAndRemoveFromPersistedList() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction1 = session.openTransaction();
+ String resourcePath = "/test1";
+ CDOResource res = transaction1.createResource(resourcePath);
+ res.getContents().add(getModel1Factory().createCompany());
+ transaction1.commit();
+
+ Supplier supplier = getModel1Factory().createSupplier();
+ PurchaseOrder purchaseOrder = getModel1Factory().createPurchaseOrder();
+ res.getContents().add(supplier);
+ res.getContents().add(purchaseOrder);
+ supplier.getPurchaseOrders().add(purchaseOrder);
+ transaction1.commit();
+
+ // This remove will generate a CDOSetFeatureDelta that will be added to a CDOListFeatureDelta. Why?
+ res.getContents().remove(purchaseOrder);
+ supplier.getPurchaseOrders().remove(purchaseOrder);
+ purchaseOrder.setSupplier(null);
+ transaction1.commit();
+ }
+
+ public void testListChanges07() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(5);
+ int[] positions = new int[5];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ orders.add(order[2]);
+
+ transaction.commit();
+
+ orders.add(0, order[0]);
+ orders.move(1, 0);
+ orders.add(0, order[1]);
+ orders.remove(1);
+ orders.add(1, order[2]);
+ orders.remove(2);
+ orders.move(1, 0);
+ orders.move(0, 1);
+ orders.remove(1);
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ positions[i] = orders.get(i).getId();
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testListChanges06() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(5);
+ int[] positions = new int[5];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ orders.add(0, order[0]);
+ orders.add(0, order[1]);
+ orders.add(0, order[2]);
+ orders.add(2, order[3]);
+ orders.remove(3);
+ orders.move(2, 0);
+ orders.add(1, order[0]);
+ orders.move(2, 1);
+ orders.move(3, 0);
+ orders.remove(0);
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ positions[i] = orders.get(i).getId();
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testListChanges05() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(5);
+ int[] positions = new int[5];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ orders.add(0, order[0]);
+ orders.add(0, order[1]);
+ orders.move(1, 0);
+ orders.add(1, order[2]);
+ orders.add(0, order[3]);
+ orders.move(1, 3);
+ orders.move(2, 3);
+ orders.add(1, order[4]);
+ orders.remove(4);
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ positions[i] = orders.get(i).getId();
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testListChanges04() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(4);
+ int[] positions = new int[4];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ orders.add(0, order[0]);
+ orders.add(0, order[1]);
+ orders.add(0, order[2]);
+ orders.move(1, 2);
+ orders.move(1, 2);
+ orders.remove(2);
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ positions[i] = orders.get(i).getId();
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testListChanges03() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(4);
+ int[] positions = new int[4];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ orders.add(0, order[0]);
+ orders.add(0, order[1]);
+ orders.add(0, order[2]);
+ orders.move(0, 1);
+ orders.remove(1);
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ positions[i] = orders.get(i).getId();
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testListChanges02() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(4);
+ int[] positions = new int[4];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ orders.add(0, order[0]);
+ orders.add(0, order[1]);
+ orders.move(0, 1);
+ orders.add(0, order[2]);
+ orders.move(2, 0);
+ orders.remove(1);
+ orders.remove(0);
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ positions[i] = orders.get(i).getId();
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testListChanges01() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(4);
+ int[] positions = new int[4];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ orders.add(0, order[0]);
+ orders.add(0, order[1]);
+ orders.add(0, order[2]);
+ orders.move(2, 0);
+ orders.remove(0);
+ orders.remove(0);
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ positions[i] = orders.get(i).getId();
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testAddMoveMoveRemove() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(4);
+ int[] positions = new int[4];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ orders.add(0, order[0]);
+ orders.add(0, order[1]);
+ orders.add(1, order[2]);
+ orders.add(2, order[3]);
+ orders.remove(0);
+ orders.add(2, order[1]);
+ orders.remove(3);
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ positions[i] = orders.get(i).getId();
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testMultipleMove() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(5);
+ int[] positions = new int[5];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ orders.add(order[0]);
+ // 0
+ orders.add(order[1]);
+ // 0,1
+ orders.add(order[2]);
+ // 0,1,2
+ orders.move(2, 0);
+ // 1,2,0
+ orders.move(1, 2);
+ // 1,0,2
+ orders.move(0, 2);
+ // 2,1,0
+ orders.remove(1);
+ // 2,0
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ positions[i] = orders.get(i).getId();
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ // assertEquals(4, orders.size());
+
+ for (int i = 0; i < orders.size(); i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testRemoveAdd() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(4);
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+ for (int i = 0; i < order.length; i++)
+ {
+ orders.add(order[i]);
+ }
+
+ transaction.commit();
+
+ orders.remove(order[2]);
+ orders.add(order[2]);
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ assertEquals(4, orders.size());
+
+ int[] array = { 0, 1, 3, 2 };
+ for (int i = 0; i < array.length; i++)
+ {
+ assertEquals(array[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testAddRemoveWithAdditionalMoves() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder[] order = createSalesOrders(4);
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+ orders.add(order[0]); // 0
+ orders.add(order[1]); // 0,1
+ orders.add(order[2]); // 0,1,2
+ orders.add(order[3]); // 0,1,2,3
+ orders.remove(order[1]); // 0,2,3
+ // We should have [order3, order0, order2] after the next move.
+ orders.move(0, 2); // 3,0,2
+ orders.add(1, order[1]); // 3,1,0,2
+ orders.remove(order[1]); // 3,0,2
+
+ transaction.commit();
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ assertEquals(3, orders.size());
+
+ int[] array = { 3, 0, 2 };
+ for (int i = 0; i < array.length; i++)
+ {
+ assertEquals(array[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testAddRemoveWithAdditionalAdds() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder[] order = createSalesOrders(3);
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ customer.getSalesOrders().add(order[0]);
+ customer.getSalesOrders().add(order[1]);
+ customer.getSalesOrders().remove(order[0]);
+ customer.getSalesOrders().add(order[2]);
+
+ transaction.commit();
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ assertEquals(2, orders.size());
+
+ int[] array = { 1, 2 };
+ for (int i = 0; i < array.length; i++)
+ {
+ assertEquals(array[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ public void testOptimizeAddRemove() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order = createSalesOrders(1)[0];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ resource.getContents().add(order);
+
+ for (int i = 0; i < 100; i++)
+ {
+ customer.getSalesOrders().add(order);
+ customer.getSalesOrders().remove(order);
+ }
+
+ transaction.commit();
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ assertEquals(0, orders.size());
+
+ transaction.close();
+ session.close();
+ }
+ }
+
+ public void testOptimizeInterleavedAddRemove() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder[] order = createSalesOrders(2);
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ for (int i = 0; i < 100; i++)
+ {
+ customer.getSalesOrders().add(order[0]);
+ customer.getSalesOrders().add(order[1]);
+ customer.getSalesOrders().remove(order[0]);
+ customer.getSalesOrders().remove(order[1]);
+ }
+
+ transaction.commit();
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ assertEquals(0, orders.size());
+
+ transaction.close();
+ session.close();
+ }
+ }
+
+ public void testOptimizeMove() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ SalesOrder order[] = createSalesOrders(4);
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+ for (int i = 0; i < order.length; i++)
+ {
+ orders.add(order[i]);
+ }
+
+ // 0,1,2,3
+ orders.move(0, 2);
+ // 2,0,1,3
+ orders.remove(0);
+ // 0,1,3
+ orders.remove(0);
+ // 1,3
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ assertEquals(2, orders.size());
+
+ int[] array = { 1, 3 };
+ for (int i = 0; i < array.length; i++)
+ {
+ assertEquals(array[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+ /**
+ * Use this test to generate random list changes. It will loop until and exception is thrown. So DO NOT ENABLE it
+ * except if you are working on this bug.
+ */
+ public void _testRandomAddRemoveMove() throws Exception
+ {
+ tearDown();
+ while (true)
+ {
+ setUp();
+ generateRandomAddRemoveMove();
+ tearDown();
+ }
+ }
+
+ private void generateRandomAddRemoveMove() throws Exception
+ {
+ // Creates a customer and commits.
+ Customer customer = getModel1Factory().createCustomer();
+ customer.setName("customer");
+
+ // Creates a new order and adds/removes it several times before committing.
+ int orderSize = 10;
+ SalesOrder order[] = createSalesOrders(orderSize);
+ int[] positions = new int[orderSize];
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource("/test1");
+ resource.getContents().add(customer);
+ transaction.commit();
+
+ for (int i = 0; i < order.length; i++)
+ {
+ resource.getContents().add(order[i]);
+ }
+
+ EList<SalesOrder> orders = customer.getSalesOrders();
+
+ // Random but not too much.
+ long time = System.currentTimeMillis();
+ System.out.println("Seed: " + time);
+ Random rnd = new Random(time);
+
+ // Pre-feed the list.
+ System.out.print("Original list: [ ");
+ for (int i = 0; i < orderSize; i++)
+ {
+ if (rnd.nextBoolean())
+ {
+ System.out.print(i + " ");
+ orders.add(order[i]);
+ }
+ }
+ System.out.println("]");
+ transaction.commit();
+
+ for (int i = 0; i < 30; i++)
+ {
+ // Add/Remove
+ if (rnd.nextBoolean())
+ {
+ // Add
+ if (rnd.nextBoolean())
+ {
+ boolean success = false;
+ for (int j = 0; j < order.length; j++)
+ {
+ if (!orders.contains(order[j]))
+ {
+ int index = rnd.nextInt(orders.size() == 0 ? 1 : orders.size());
+ System.out.println("ADD " + order[j].getId() + " at " + index);
+ orders.add(index, order[j]);
+ success = true;
+ break;
+ }
+ }
+ if (!success)
+ {
+ int nextInt = rnd.nextInt(orderSize);
+ System.out.println("REMOVE " + nextInt);
+ orders.remove(nextInt);
+ }
+ }
+ // Remove
+ else
+ {
+ if (orders.size() > 0)
+ {
+ int nextInt = rnd.nextInt(orders.size());
+ System.out.println("REMOVE " + nextInt);
+ orders.remove(nextInt);
+ }
+ else
+ { // Not super random but who cares?
+ int index = rnd.nextInt(orders.size() == 0 ? 1 : orders.size());
+ System.out.println("ADD " + order[0].getId() + " at " + index);
+ orders.add(index, order[0]);
+ }
+ }
+ }
+ // Move
+ else
+ {
+ int size = orders.size();
+ if (size > 1)
+ {
+ int to = rnd.nextInt(size);
+ int from = rnd.nextInt(size);
+ System.out.println("MOVE " + from + " => " + to);
+ orders.move(to, from);
+ }
+ }
+ }
+
+ // System.out.println("==========");
+
+ // And the result is...
+ for (int i = 0; i < positions.length; i++)
+ {
+ positions[i] = i < orders.size() ? orders.get(i).getId() : -1;
+ // System.out.println(i + " => " + positions[i]);
+ }
+
+ transaction.commit();
+
+ session.close();
+ }
+
+ System.out.println("==========");
+
+ // Checks that the other transaction got the right invalidation.
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource("/test1");
+
+ Customer testCustomer = (Customer)resource.getContents().get(0);
+ EList<SalesOrder> orders = testCustomer.getSalesOrders();
+
+ for (int i = 0; i < positions.length && positions[i] != -1; i++)
+ {
+ System.out.println(positions[i] + " => " + orders.get(i).getId());
+ }
+ for (int i = 0; i < positions.length && positions[i] != -1; i++)
+ {
+ assertEquals(positions[i], orders.get(i).getId());
+ }
+
+ transaction.close();
+ session.close();
+ }
+
+ }
+
+}

Back to the top