diff options
| author | Maxime Porhel | 2017-04-19 09:12:21 +0000 |
|---|---|---|
| committer | Maxime Porhel | 2017-04-28 08:11:32 +0000 |
| commit | 2ae0818a840c77faa776e855c4d603f7123980a4 (patch) | |
| tree | ecf53c712992d67a596bd7876b97198e6b76e256 | |
| parent | 015fdd54cf4d578a48f4a0990092ce722d443322 (diff) | |
| download | org.eclipse.sirius-2ae0818a840c77faa776e855c4d603f7123980a4.tar.gz org.eclipse.sirius-2ae0818a840c77faa776e855c4d603f7123980a4.tar.xz org.eclipse.sirius-2ae0818a840c77faa776e855c4d603f7123980a4.zip | |
[515819] Do not lose the cross referencer after DND to resource root
Sometimes the model element contents and cross references are modified
before the REMOVE notification. If an object is dropped as a new
resource root, it has no container after the move to
resource.getContents(), the eContainer() is null but the element is
still contained in a resource (which has the cross ref adapter) so it
should not be removed or we will a sub-tree of the model without the
semantic cross referencer.
Bug: 515819
Cherry-picked-from: 515684
Change-Id: Ieecc9f652abf7a692745ad4fa6af6b435d5b618b
Signed-off-by: Maxime Porhel <maxime.porhel@obeo.fr>
2 files changed, 83 insertions, 20 deletions
diff --git a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/LazyCrossReferencer.java b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/LazyCrossReferencer.java index 516dbd17d4..23665544a6 100644 --- a/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/LazyCrossReferencer.java +++ b/plugins/org.eclipse.sirius.common/src/org/eclipse/sirius/common/tools/api/util/LazyCrossReferencer.java @@ -21,7 +21,8 @@ import org.eclipse.emf.ecore.resource.Resource; import com.google.common.collect.Iterables; /** - * A lazy cross referencer which does nothing until one of its method is called. <BR> + * A lazy cross referencer which does nothing until one of its method is called. + * <BR> * <BR> * This cross referencer also reacts to {@link EObject} removal from their * containing reference : it removes itself automatically from their adapters @@ -192,7 +193,11 @@ public class LazyCrossReferencer extends ECrossReferenceAdapterWithUnproxyCapabi /** * This method does not remove the adapter from the notification old value - * if its new container is already set and also has the adapter. + * in two cases: + * <ul> + * <li>if its new container is already set and also has the adapter</li> + * <li>if the element is now a root of a resource which has the adapter</li> + * </ul> * * @param notification * a containment notification @@ -203,7 +208,12 @@ public class LazyCrossReferencer extends ECrossReferenceAdapterWithUnproxyCapabi boolean toRemove = true; if (oldValue instanceof EObject) { - EObject currentContainer = ((EObject) oldValue).eContainer(); + EObject removedEObject = (EObject) oldValue; + + Notifier currentContainer = removedEObject.eContainer(); + if (currentContainer == null) { + currentContainer = removedEObject.eResource(); + } if (currentContainer != null && currentContainer != notification.getNotifier() && currentContainer.eAdapters().contains(this)) { toRemove = false; diff --git a/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/common/SiriusCrossReferenceAdapterTests.java b/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/common/SiriusCrossReferenceAdapterTests.java index fd98b27099..331b1c2ea2 100644 --- a/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/common/SiriusCrossReferenceAdapterTests.java +++ b/plugins/org.eclipse.sirius.tests.junit/src/org/eclipse/sirius/tests/unit/common/SiriusCrossReferenceAdapterTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 THALES GLOBAL SERVICES. + * Copyright (c) 2015, 2017 THALES GLOBAL SERVICES 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 @@ -16,8 +16,14 @@ import java.util.Iterator; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.common.command.IdentityCommand; import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.transaction.RecordingCommand; @@ -28,14 +34,14 @@ import org.eclipse.sirius.common.tools.api.util.LazyCrossReferencer; import org.eclipse.sirius.common.tools.api.util.SiriusCrossReferenceAdapter; import org.eclipse.sirius.tests.sample.component.Component; import org.eclipse.sirius.tests.sample.component.ComponentFactory; +import org.eclipse.sirius.tests.sample.component.ComponentPackage; import org.eclipse.sirius.tests.support.api.SiriusTestCase; import org.eclipse.sirius.tools.api.command.ICommandFactory; import org.eclipse.sirius.viewpoint.DAnalysisSessionEObject; /** - * Class containing tests to update of {@link SiriusCrossReferenceAdapter} after - * CRUD action on resources through DAnalysisSessionImpl such - * unload/reload/remove resource, close session. + * Class containing tests to update of {@link SiriusCrossReferenceAdapter} after CRUD action on resources through + * DAnalysisSessionImpl such unload/reload/remove resource, close session. * * @author <a href="mailto:laurent.fasani@obeo.fr">Laurent Fasani</a> */ @@ -50,18 +56,19 @@ public class SiriusCrossReferenceAdapterTests extends SiriusTestCase { super.setUp(); setWarningCatchActive(true); + // create session with empty aird + genericSetUp(); + + // add semantic resources + initSemanticResource(); } /** - * Check that fragmented resource is not reloaded during its unload when it - * has been externally modified. + * Check that fragmented resource is not reloaded during its unload when it has been externally modified. * * @throws Exception */ public void testDisablingCrossReferencerWhileReloadingResource() throws Exception { - genericSetUp(); - - initSemanticResource(); // check that semantic crossRefAdapter is set on fragmented resource Resource fragmentedResource = ((DAnalysisSessionEObject) session).getControlledResources().get(0); @@ -93,19 +100,12 @@ public class SiriusCrossReferenceAdapterTests extends SiriusTestCase { } /** - * Check that fragmented resource is not reloaded during its unload when it - * has been externally deleted. + * Check that fragmented resource is not reloaded during its unload when it has been externally deleted. * * @throws Exception */ public void testDisablingCrossReferencerWhileDeletingResource() throws Exception { - // create session with empty aird - genericSetUp(); - - // add semantic resources - initSemanticResource(); - // simulation of DELETION of fragmentResource File fragFile = ResourcesPlugin.getWorkspace().getRoot().getProject(TEMPORARY_PROJECT_NAME).getFile(FRAGMENT_FILE_NAME).getLocation().toFile(); fragFile.delete(); @@ -129,6 +129,59 @@ public class SiriusCrossReferenceAdapterTests extends SiriusTestCase { } /** + * Check that if that the session cross referencer is not removed if a REMOVE notification is handled after the add, + * ie the old value is already added to a resource with the same cross reference adapter. + * + * @throws Exception + */ + public void testNoAdapterRemovalAfterLateRemoveNotificationReception() throws Exception { + // Check the initial check. + checkCrossReferenceIsInstalledOnAllSemanticElements(); + + final Component compoRoot = (Component) session.getSemanticResources().iterator().next().getContents().get(0); + final Component compo1 = compoRoot.getChildren().get(0); + final Component compo2 = compo1.getChildren().get(0); + + // DND compo2 as second root of the semantic resource + session.getTransactionalEditingDomain().getCommandStack().execute(new RecordingCommand(session.getTransactionalEditingDomain()) { + + @Override + protected void doExecute() { + compo1.getChildren().remove(compo2); + session.getSemanticResources().iterator().next().getContents().add(compo2); + } + }); + + // Check the lazy cross referencer installation + checkCrossReferenceIsInstalledOnAllSemanticElements(); + + // Simulate the reception of a late reception of the REMOVE notification + session.getTransactionalEditingDomain().getCommandStack().execute(new IdentityCommand() { + @Override + public void execute() { + Notification removeNotification = new ENotificationImpl((InternalEObject) compo1, Notification.REMOVE, ComponentPackage.Literals.COMPONENT__CHILDREN, compo2, null); + compo1.eNotify(removeNotification); + } + }); + + // Check the lazy cross referencer installation + checkCrossReferenceIsInstalledOnAllSemanticElements(); + } + + private void checkCrossReferenceIsInstalledOnAllSemanticElements() { + for (Resource res : session.getSemanticResources()) { + assertTrue("The semantic cross referencer is not installed on the resource " + res.getURI(), res.eAdapters().contains(session.getSemanticCrossReferencer())); + + TreeIterator<EObject> eAllContents = res.getAllContents(); + while (eAllContents.hasNext()) { + EObject obj = eAllContents.next(); + assertTrue("The semantic cross referencer is not installed on " + obj, obj.eAdapters().contains(session.getSemanticCrossReferencer())); + } + + } + } + + /** * Initialize semantic resources */ private void initSemanticResource() { |
