diff options
author | Eike Stepper | 2012-02-23 11:12:19 +0000 |
---|---|---|
committer | Eike Stepper | 2012-02-23 11:12:19 +0000 |
commit | ac288aab2f62782dec79a51617d3629f40649433 (patch) | |
tree | c0ba70948335ed0d24a354bcb02f54ad28247607 | |
parent | df68045fd2b45732b5ba240c8afe83ca239d92cb (diff) | |
download | cdo-ac288aab2f62782dec79a51617d3629f40649433.tar.gz cdo-ac288aab2f62782dec79a51617d3629f40649433.tar.xz cdo-ac288aab2f62782dec79a51617d3629f40649433.zip |
372311: [Legacy] eContainer changes not properly propagated
https://bugs.eclipse.org/bugs/show_bug.cgi?id=372311
2 files changed, 399 insertions, 187 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_372307_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_372307_Test.java new file mode 100644 index 0000000000..abc81c27d2 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_372307_Test.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2004 - 2012 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: + * Steve Monnier - initial API and implementation + */ +package org.eclipse.emf.cdo.tests.bugzilla; + +import org.eclipse.emf.cdo.common.id.CDOID; +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.model6.A; +import org.eclipse.emf.cdo.tests.model6.B; +import org.eclipse.emf.cdo.tests.model6.C; +import org.eclipse.emf.cdo.tests.model6.D; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.util.CDOUtil; + +import org.eclipse.emf.common.util.EList; + +/** + * @author Steve Monnier + */ +public class Bugzilla_372307_Test extends AbstractCDOTest +{ + public void testMoveElementToOtherContainer() throws Exception + { + A session1a1 = getModel6Factory().createA(); + A session1a2 = getModel6Factory().createA(); + D session1d = getModel6Factory().createD(); + + session1a1.getOwnedDs().add(session1d); + + // Create model using session1 + CDOSession session1 = openSession(); + CDOTransaction transaction1 = session1.openTransaction(); + CDOResource resource1 = transaction1.createResource(getResourcePath("myResource")); + resource1.getContents().add(session1a1); + resource1.getContents().add(session1a2); + transaction1.commit(); + + System.out.println("a1: " + CDOUtil.getCDOObject(session1a1)); + System.out.println("a2: " + CDOUtil.getCDOObject(session1a2)); + System.out.println("d: " + CDOUtil.getCDOObject(session1d)); + + // Open a second session on the shared resource + CDOSession session2 = openSession(); + CDOTransaction transaction2 = session2.openTransaction(); + CDOResource resource2 = transaction2.getResource(getResourcePath("myResource"), true); + A session2a1 = (A)resource2.getContents().get(0); + A session2a2 = (A)resource2.getContents().get(1); + D session2d = session2a1.getOwnedDs().get(0); + + // Move the D element from parent A1 to A2 in session1 and commit + EList<D> ownedDs = session1a2.getOwnedDs(); + ownedDs.add(session1d); + commitAndSync(transaction1, transaction2); + + // Validate that A1 has no content in both sessions + assertEquals("A1 in session1 is expected to be empty", 0, session1a1.eContents().size()); + assertEquals("A1 in session2 is expected to be empty", 0, session2a1.eContents().size()); + + // Validate that A2 contains D in both sessions + assertEquals("A2 in session1 is expected to have contents", 1, session1a2.eContents().size()); + assertEquals("A2 in session2 is expected to have contents", 1, session2a2.eContents().size()); + + CDOID id1 = CDOUtil.getCDOObject(session1a2.eContents().get(0)).cdoID(); + CDOID id2 = CDOUtil.getCDOObject(session2a2.eContents().get(0)).cdoID(); + assertEquals("Element contained in A1 should have the same CDOID in both sessions", id1, id2); + + // Validate that the container of the D element is the same in both sessions + id1 = CDOUtil.getCDOObject(session1d.eContainer()).cdoID(); + id2 = CDOUtil.getCDOObject(session2d.eContainer()).cdoID(); + assertEquals("Container of D should have the same CDOID in both sessions", id1, id2); + } + + public void testMoveElementToOtherContainerSingleValued() throws Exception + { + B session1a1 = getModel6Factory().createB(); + B session1a2 = getModel6Factory().createB(); + C session1d = getModel6Factory().createC(); + + session1a1.setOwnedC(session1d); + + // Create model using session1 + CDOSession session1 = openSession(); + CDOTransaction transaction1 = session1.openTransaction(); + CDOResource resource1 = transaction1.createResource(getResourcePath("myResource")); + resource1.getContents().add(session1a1); + resource1.getContents().add(session1a2); + transaction1.commit(); + + System.out.println("a1: " + CDOUtil.getCDOObject(session1a1)); + System.out.println("a2: " + CDOUtil.getCDOObject(session1a2)); + System.out.println("d: " + CDOUtil.getCDOObject(session1d)); + + // Move the D element from parent A1 to A2 in session1 and commit + session1a2.setOwnedC(session1d); + transaction1.commit(); + + // Open a second session on the shared resource + CDOSession session2 = openSession(); + CDOTransaction transaction2 = session2.openTransaction(); + C session2d = transaction2.getObject(session1d); + + assertEquals(CDOUtil.getCDOObject(session1a2).cdoID(), CDOUtil.getCDOObject(session2d.eContainer()).cdoID()); + } +} diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyAdapter.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyAdapter.java index dc4b6f1300..1719a506a7 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyAdapter.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyAdapter.java @@ -1,187 +1,286 @@ -/*
- * Copyright (c) 2004 - 2012 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
- * Martin Fluegge - bug 247226: Transparently support legacy models
- */
-package org.eclipse.emf.internal.cdo.object;
-
-import org.eclipse.emf.cdo.CDONotification;
-import org.eclipse.emf.cdo.common.model.EMFUtil;
-import org.eclipse.emf.cdo.transaction.CDOTransaction;
-
-import org.eclipse.emf.internal.cdo.bundle.OM;
-
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-
-import org.eclipse.emf.common.notify.Adapter;
-import org.eclipse.emf.common.notify.Notification;
-import org.eclipse.emf.common.notify.Notifier;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.InternalEObject;
-import org.eclipse.emf.spi.cdo.CDOStore;
-import org.eclipse.emf.spi.cdo.FSMUtil;
-
-import java.util.List;
-
-/**
- * @author Eike Stepper
- * @since 2.0
- */
-public class CDOLegacyAdapter extends CDOLegacyWrapper implements Adapter.Internal
-{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_OBJECT, CDOLegacyAdapter.class);
-
- /**
- * @since 3.0
- */
- public CDOLegacyAdapter(InternalEObject object)
- {
- super(object);
-
- instance.eAdapters().add(this);
- ((org.eclipse.emf.common.notify.impl.BasicNotifierImpl.EObservableAdapterList)instance.eAdapters())
- .addListener(new AdapterListListener());
- }
-
- public void setTarget(Notifier newTarget)
- {
- instance = (InternalEObject)newTarget;
- }
-
- public void unsetTarget(Notifier oldTarget)
- {
- if (instance == oldTarget)
- {
- instance = null;
- }
- }
-
- public Notifier getTarget()
- {
- return instance;
- }
-
- public boolean isAdapterForType(Object type)
- {
- return type == CDOLegacyAdapter.class;
- }
-
- public void notifyChanged(Notification msg)
- {
- if (msg.isTouch() || msg instanceof CDONotification)
- {
- return;
- }
-
- EStructuralFeature feature = (EStructuralFeature)msg.getFeature();
- if (view == null || feature == null || !(view instanceof CDOTransaction))
- {
- return;
- }
-
- CDOStore store = view.getStore();
- if (EMFUtil.isPersistent(feature))
- {
- switch (msg.getEventType())
- {
- case Notification.SET:
- store.set(instance, feature, msg.getPosition(), msg.getNewValue());
- break;
-
- case Notification.UNSET:
- store.unset(instance, feature);
- break;
-
- case Notification.MOVE:
- // TODO Is that correct?
- store.move(instance, feature, msg.getPosition(), (Integer)msg.getOldValue());
- break;
-
- case Notification.ADD:
- store.add(instance, feature, msg.getPosition(), msg.getNewValue());
- break;
-
- case Notification.ADD_MANY:
- {
- int pos = msg.getPosition();
- @SuppressWarnings("unchecked")
- List<Object> list = (List<Object>)msg.getNewValue();
- for (Object object : list)
- {
- store.add(instance, feature, pos++, object);
- }
-
- break;
- }
-
- case Notification.REMOVE:
- {
- store.remove(instance, feature, msg.getPosition());
- break;
- }
-
- case Notification.REMOVE_MANY:
- {
- @SuppressWarnings("unchecked")
- List<Object> list = (List<Object>)msg.getOldValue();
- for (int i = list.size() - 1; i >= 0; --i)
- {
- store.remove(instance, feature, i);
- }
-
- break;
- }
- }
-
- // Align Container for bidirectional references because this is not set in the store. See Bugzilla_246622_Test
- instanceToRevisionContainment();
- }
- }
-
- /**
- * @author Martin Flügge
- * @since 3.0
- */
- protected class AdapterListListener implements
- org.eclipse.emf.common.notify.impl.BasicNotifierImpl.EObservableAdapterList.Listener
- {
- /**
- * @since 4.0
- */
- public AdapterListListener()
- {
- }
-
- public void added(Notifier notifier, Adapter adapter)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Added : {0} to {1} ", adapter, CDOLegacyAdapter.this); //$NON-NLS-1$
- }
-
- if (!FSMUtil.isTransient(CDOLegacyAdapter.this))
- {
- cdoView().handleAddAdapter(CDOLegacyAdapter.this, adapter);
- }
- }
-
- public void removed(Notifier notifier, Adapter adapter)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Removed : {0} from {1} ", adapter, CDOLegacyAdapter.this); //$NON-NLS-1$
- }
-
- if (!FSMUtil.isTransient(CDOLegacyAdapter.this))
- {
- cdoView().handleRemoveAdapter(CDOLegacyAdapter.this, adapter);
- }
- }
- }
-}
+/* + * Copyright (c) 2004 - 2012 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 + * Martin Fluegge - bug 247226: Transparently support legacy models + */ +package org.eclipse.emf.internal.cdo.object; + +import org.eclipse.emf.cdo.CDONotification; +import org.eclipse.emf.cdo.common.model.EMFUtil; +import org.eclipse.emf.cdo.transaction.CDOTransaction; +import org.eclipse.emf.cdo.util.CDOUtil; + +import org.eclipse.emf.internal.cdo.CDOObjectImpl; +import org.eclipse.emf.internal.cdo.bundle.OM; + +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.Notifier; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.spi.cdo.CDOStore; +import org.eclipse.emf.spi.cdo.FSMUtil; + +import java.util.List; + +/** + * @author Eike Stepper + * @since 2.0 + */ +public class CDOLegacyAdapter extends CDOLegacyWrapper implements Adapter.Internal +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_OBJECT, CDOLegacyAdapter.class); + + /** + * @since 3.0 + */ + public CDOLegacyAdapter(InternalEObject object) + { + super(object); + + instance.eAdapters().add(this); + ((org.eclipse.emf.common.notify.impl.BasicNotifierImpl.EObservableAdapterList)instance.eAdapters()) + .addListener(new AdapterListListener()); + } + + public void setTarget(Notifier newTarget) + { + instance = (InternalEObject)newTarget; + } + + public void unsetTarget(Notifier oldTarget) + { + if (instance == oldTarget) + { + instance = null; + } + } + + public Notifier getTarget() + { + return instance; + } + + public boolean isAdapterForType(Object type) + { + return type == CDOLegacyAdapter.class; + } + + public void notifyChanged(Notification msg) + { + if (msg.isTouch() || msg instanceof CDONotification) + { + return; + } + + EStructuralFeature feature = (EStructuralFeature)msg.getFeature(); + if (view == null || feature == null || !(view instanceof CDOTransaction)) + { + return; + } + + CDOStore store = view.getStore(); + if (EMFUtil.isPersistent(feature)) + { + int eventType = msg.getEventType(); + int position = msg.getPosition(); + Object oldValue = msg.getOldValue(); + Object newValue = msg.getNewValue(); + + switch (eventType) + { + case Notification.SET: + { + store.set(instance, feature, position, newValue); + if (feature instanceof EReference) + { + EReference reference = (EReference)feature; + if (reference.isContainment()) + { + if (oldValue != null) + { + InternalEObject oldChild = (InternalEObject)oldValue; + setContainer(store, oldChild, null, 0); + } + + if (newValue != null) + { + InternalEObject newChild = (InternalEObject)newValue; + setContainer(store, newChild, this, reference.getFeatureID()); + } + } + } + + break; + } + + case Notification.UNSET: + { + if (feature instanceof EReference) + { + EReference reference = (EReference)feature; + if (reference.isContainment()) + { + @SuppressWarnings("unchecked") + List<Object> list = (List<Object>)oldValue; + for (Object child : list) + { + if (child != null) + { + setContainer(store, (InternalEObject)child, null, 0); + } + } + } + } + + store.unset(instance, feature); + break; + } + + case Notification.MOVE: + store.move(instance, feature, position, (Integer)oldValue); + break; + + case Notification.ADD: + store.add(instance, feature, position, newValue); + if (newValue != null && feature instanceof EReference) + { + EReference reference = (EReference)feature; + if (reference.isContainment()) + { + InternalEObject newChild = (InternalEObject)newValue; + setContainer(store, newChild, this, reference.getFeatureID()); + } + } + + break; + + case Notification.ADD_MANY: + { + int pos = position; + @SuppressWarnings("unchecked") + List<Object> list = (List<Object>)newValue; + for (Object object : list) + { + store.add(instance, feature, pos++, object); + if (object != null && feature instanceof EReference) + { + EReference reference = (EReference)feature; + if (reference.isContainment()) + { + InternalEObject newChild = (InternalEObject)object; + setContainer(store, newChild, this, reference.getFeatureID()); + } + } + } + + break; + } + + case Notification.REMOVE: + { + InternalEObject oldChild = (InternalEObject)store.remove(instance, feature, position); + if (oldChild != null && feature instanceof EReference) + { + EReference reference = (EReference)feature; + if (reference.isContainment()) + { + setContainer(store, oldChild, null, 0); + } + } + break; + } + + case Notification.REMOVE_MANY: + { + @SuppressWarnings("unchecked") + List<Object> list = (List<Object>)oldValue; + for (int i = list.size() - 1; i >= 0; --i) + { + InternalEObject oldChild = (InternalEObject)store.remove(instance, feature, i); + if (oldChild != null && feature instanceof EReference) + { + EReference reference = (EReference)feature; + if (reference.isContainment()) + { + setContainer(store, oldChild, null, 0); + } + } + } + + break; + } + } + + // Align Container for bidirectional references because this is not set in the store. See Bugzilla_246622_Test + instanceToRevisionContainment(); + } + } + + private void setContainer(CDOStore store, InternalEObject object, InternalEObject container, int containingFeatureID) + { + if (object instanceof CDOObjectImpl) + { + // Don't touch native objects + return; + } + + if (FSMUtil.isTransient(CDOUtil.getCDOObject(object))) + { + // Don't touch transient objects + return; + } + + store.setContainer(object, null, container, containingFeatureID); + } + + /** + * @author Martin Flügge + * @since 3.0 + */ + protected class AdapterListListener implements + org.eclipse.emf.common.notify.impl.BasicNotifierImpl.EObservableAdapterList.Listener + { + /** + * @since 4.0 + */ + public AdapterListListener() + { + } + + public void added(Notifier notifier, Adapter adapter) + { + if (TRACER.isEnabled()) + { + TRACER.format("Added : {0} to {1} ", adapter, CDOLegacyAdapter.this); //$NON-NLS-1$ + } + + if (!FSMUtil.isTransient(CDOLegacyAdapter.this)) + { + cdoView().handleAddAdapter(CDOLegacyAdapter.this, adapter); + } + } + + public void removed(Notifier notifier, Adapter adapter) + { + if (TRACER.isEnabled()) + { + TRACER.format("Removed : {0} from {1} ", adapter, CDOLegacyAdapter.this); //$NON-NLS-1$ + } + + if (!FSMUtil.isTransient(CDOLegacyAdapter.this)) + { + cdoView().handleRemoveAdapter(CDOLegacyAdapter.this, adapter); + } + } + } +} |