summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaspar De Groot2010-01-18 05:09:01 (EST)
committerCaspar De Groot2010-01-18 05:09:01 (EST)
commitda6dfefe10ed83dc74009c7424832d4d6f91cb7b (patch)
tree6b4cf922c59718e68e33e8273eec78b7b1f72ab0
parent0f2b4f6f447342287deaf0ef68d6b25bfbefcca9 (diff)
downloadcdo-da6dfefe10ed83dc74009c7424832d4d6f91cb7b.zip
cdo-da6dfefe10ed83dc74009c7424832d4d6f91cb7b.tar.gz
cdo-da6dfefe10ed83dc74009c7424832d4d6f91cb7b.tar.bz2
[298561] Uncommitted dangling references not removed on passiveUpdate/refresh
https://bugs.eclipse.org/bugs/show_bug.cgi?id=298561
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java4
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_298561_Test.java233
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java42
3 files changed, 278 insertions, 1 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java
index 27fb76e..0676fe5 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsAllConfigs.java
@@ -63,6 +63,7 @@ import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_289984_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_292372_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_294850_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_294859_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_298561_Test;
import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_299190_Test;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTestSuite;
@@ -180,8 +181,9 @@ public abstract class AllTestsAllConfigs extends ConfigTestSuite
testClasses.add(Bugzilla_294850_Test.class);
testClasses.add(Bugzilla_294859_Test.class);
testClasses.add(Bugzilla_292372_Test.class);
+ testClasses.add(Bugzilla_298561_Test.class);
testClasses.add(Bugzilla_299190_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/bugzilla/Bugzilla_298561_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_298561_Test.java
new file mode 100644
index 0000000..454ae09
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_298561_Test.java
@@ -0,0 +1,233 @@
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.CDOState;
+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.model4.ContainedElementNoOpposite;
+import org.eclipse.emf.cdo.tests.model4.RefMultiNonContainedNPL;
+import org.eclipse.emf.cdo.tests.model4.RefSingleNonContainedNPL;
+import org.eclipse.emf.cdo.tests.model4.model4Factory;
+import org.eclipse.emf.cdo.tests.model4.model4Package;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.ObjectNotFoundException;
+
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+public class Bugzilla_298561_Test extends AbstractCDOTest
+{
+ private static String RESOURCENAME = "/r1";
+
+ public void test_new()
+ {
+ CDOSession session = openSession();
+ session.options().setPassiveUpdateEnabled(false);
+ session.getPackageRegistry().putEPackage(model4Package.eINSTANCE);
+
+ CDOTransaction tx = session.openTransaction();
+ CDOResource r1 = tx.createResource(RESOURCENAME);
+
+ // Create referencee and store it
+ ContainedElementNoOpposite referencee = model4Factory.eINSTANCE.createContainedElementNoOpposite();
+ r1.getContents().add(referencee);
+ tx.commit();
+
+ // Create referencer, don't store it -- keep it as NEW
+ RefSingleNonContainedNPL referencer = model4Factory.eINSTANCE.createRefSingleNonContainedNPL();
+ r1.getContents().add(referencer);
+ referencer.setElement(referencee);
+ assertEquals(CDOState.NEW, ((CDOObject)referencer).cdoState());
+
+ // Delete the referencee in 2nd session
+ doSecondSession();
+
+ // Refresh
+ session.refresh();
+
+ //
+ try
+ {
+ boolean isSet = referencer.eIsSet(model4Package.eINSTANCE.getRefSingleNonContainedNPL_Element());
+ System.out.println("---> " + isSet);
+
+ if (isSet)
+ {
+ ContainedElementNoOpposite e = referencer.getElement();
+ System.out.println("---> " + e);
+ }
+ }
+ catch (ObjectNotFoundException e)
+ {
+ fail("Should not have thrown ObjectNotFoundException");
+ }
+
+ tx.close();
+ session.close();
+ }
+
+ public void test_dirty()
+ {
+ CDOSession session = openSession();
+ session.options().setPassiveUpdateEnabled(false);
+ session.getPackageRegistry().putEPackage(model4Package.eINSTANCE);
+
+ CDOTransaction tx = session.openTransaction();
+ CDOResource r1 = tx.createResource(RESOURCENAME);
+
+ // Create referencee and store it
+ ContainedElementNoOpposite referencee = model4Factory.eINSTANCE.createContainedElementNoOpposite();
+ r1.getContents().add(referencee);
+ tx.commit();
+
+ System.out.println("---> " + ((CDOObject)referencee).cdoID());
+
+ // Create referencer, store it, then make it DIRTY
+ RefSingleNonContainedNPL referencer = model4Factory.eINSTANCE.createRefSingleNonContainedNPL();
+ r1.getContents().add(referencer);
+ referencer.setElement(referencee);
+ tx.commit();
+ referencer.setElement(null);
+ referencer.setElement(referencee);
+ assertEquals(CDOState.DIRTY, ((CDOObject)referencer).cdoState());
+
+ // Delete the referencee in 2nd session
+ doSecondSession();
+
+ // Refresh
+ session.refresh();
+
+ //
+ try
+ {
+ boolean isSet = referencer.eIsSet(model4Package.eINSTANCE.getRefSingleNonContainedNPL_Element());
+ System.out.println("---> " + isSet);
+
+ if (isSet)
+ {
+ ContainedElementNoOpposite e = referencer.getElement();
+ System.out.println("---> " + e);
+ }
+ }
+ catch (ObjectNotFoundException e)
+ {
+ fail("Should not have thrown ObjectNotFoundException");
+ }
+
+ tx.close();
+ session.close();
+ }
+
+ private void doSecondSession()
+ {
+ CDOSession session = openModel1Session();
+ CDOTransaction tx = session.openTransaction();
+ CDOResource r1 = tx.getResource(RESOURCENAME);
+ ContainedElementNoOpposite referencee = (ContainedElementNoOpposite)r1.getContents().get(0);
+ EcoreUtil.delete(referencee);
+ tx.commit();
+ tx.close();
+ session.close();
+ }
+
+ public void test_new_multi()
+ {
+ CDOSession session = openSession();
+ session.options().setPassiveUpdateEnabled(false);
+ session.getPackageRegistry().putEPackage(model4Package.eINSTANCE);
+
+ CDOTransaction tx = session.openTransaction();
+ CDOResource r1 = tx.createResource(RESOURCENAME);
+
+ // Create referencee and store it
+ ContainedElementNoOpposite referencee = model4Factory.eINSTANCE.createContainedElementNoOpposite();
+ r1.getContents().add(referencee);
+ tx.commit();
+
+ System.out.println("---> " + ((CDOObject)referencee).cdoID());
+
+ // Create referencer, don't store it -- keep it as NEW
+ RefMultiNonContainedNPL referencer = model4Factory.eINSTANCE.createRefMultiNonContainedNPL();
+ r1.getContents().add(referencer);
+ referencer.getElements().add(referencee);
+ assertEquals(CDOState.NEW, ((CDOObject)referencer).cdoState());
+
+ // Delete the referencee in 2nd session
+ doSecondSession();
+
+ // Refresh
+ session.refresh();
+
+ //
+ try
+ {
+ boolean isSet = referencer.eIsSet(model4Package.eINSTANCE.getRefMultiNonContainedNPL_Elements());
+ System.out.println("---> " + isSet);
+
+ if (isSet && referencer.getElements().size() > 0)
+ {
+ ContainedElementNoOpposite e = referencer.getElements().get(0);
+ System.out.println("---> " + e);
+ }
+ }
+ catch (ObjectNotFoundException e)
+ {
+ fail("Should not have thrown ObjectNotFoundException");
+ }
+
+ tx.close();
+ session.close();
+ }
+
+ public void test_dirty_multi()
+ {
+ CDOSession session = openSession();
+ session.options().setPassiveUpdateEnabled(false);
+ session.getPackageRegistry().putEPackage(model4Package.eINSTANCE);
+
+ CDOTransaction tx = session.openTransaction();
+ CDOResource r1 = tx.createResource(RESOURCENAME);
+
+ // Create referencee and store it
+ ContainedElementNoOpposite referencee = model4Factory.eINSTANCE.createContainedElementNoOpposite();
+ r1.getContents().add(referencee);
+ tx.commit();
+
+ System.out.println("---> " + ((CDOObject)referencee).cdoID());
+
+ // Create referencer, store it, then make it DIRTY
+ RefMultiNonContainedNPL referencer = model4Factory.eINSTANCE.createRefMultiNonContainedNPL();
+ r1.getContents().add(referencer);
+ referencer.getElements().add(referencee);
+ tx.commit();
+ referencer.getElements().remove(referencee);
+ referencer.getElements().add(referencee);
+ assertEquals(CDOState.DIRTY, ((CDOObject)referencer).cdoState());
+
+ // Delete the referencee in 2nd session
+ doSecondSession();
+
+ // Refresh
+ session.refresh();
+
+ //
+ try
+ {
+ boolean isSet = referencer.eIsSet(model4Package.eINSTANCE.getRefMultiNonContainedNPL_Elements());
+ System.out.println("---> " + isSet);
+
+ if (isSet && referencer.getElements().size() > 0)
+ {
+ ContainedElementNoOpposite e = referencer.getElements().get(0);
+ System.out.println("---> " + e);
+ }
+ }
+ catch (ObjectNotFoundException e)
+ {
+ fail("Should not have thrown ObjectNotFoundException");
+ }
+
+ tx.close();
+ session.close();
+ }
+}
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 7e88932..8cc3e29 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
@@ -77,7 +77,14 @@ import org.eclipse.net4j.util.options.OptionsEvent;
import org.eclipse.net4j.util.transaction.TransactionException;
import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.EStructuralFeature.Setting;
+import org.eclipse.emf.ecore.util.EContentsEList;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.EContentsEList.FeatureIterator;
import org.eclipse.emf.spi.cdo.CDOTransactionStrategy;
import org.eclipse.emf.spi.cdo.InternalCDOObject;
import org.eclipse.emf.spi.cdo.InternalCDOSavepoint;
@@ -1581,6 +1588,41 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa
}
/**
+ * @since 3.0
+ */
+ @Override
+ public Set<CDOObject> handleInvalidationWithoutNotification(Set<CDOIDAndVersion> dirtyOIDs,
+ Collection<CDOID> detachedOIDs, Set<InternalCDOObject> dirtyObjects, Set<InternalCDOObject> detachedObjects)
+ {
+ // Bugzilla 298561: This override removes references to remotely
+ // detached objects that are present in any DIRTY or NEW objects
+
+ removeCrossReferences(getDirtyObjects().values(), detachedOIDs);
+ removeCrossReferences(getNewObjects().values(), detachedOIDs);
+
+ return super.handleInvalidationWithoutNotification(dirtyOIDs, detachedOIDs, dirtyObjects, detachedObjects);
+ }
+
+ private void removeCrossReferences(Collection<CDOObject> objects, Collection<CDOID> referencedOIDs)
+ {
+ for (CDOObject object : objects)
+ {
+ for (EContentsEList.FeatureIterator<EObject> it = (FeatureIterator<EObject>)object.eCrossReferences().iterator(); it
+ .hasNext();)
+ {
+ EObject crossReferencedObject = it.next();
+ if (crossReferencedObject instanceof CDOObject
+ && referencedOIDs.contains(((CDOObject)crossReferencedObject).cdoID()))
+ {
+ EReference eReference = (EReference)it.feature();
+ Setting setting = ((InternalEObject)object).eSetting(eReference);
+ EcoreUtil.remove(setting, crossReferencedObject);
+ }
+ }
+ }
+ }
+
+ /**
* @author Simon McDuff
*/
private final class CDOCommitContextImpl implements InternalCDOCommitContext