Bug 512666: [tool] removing a Protocol with a Generalization only removes the Collaboration

Fix exceptions in deletion of a protocol for which the façade element
had previously been created and presented in the Properties View and,
then, in undo of that deletion.

https://bugs.eclipse.org/bugs/show_bug.cgi?id=512666

Change-Id: I05b3d14629ec2479ca784857ac689be43258cd9b
diff --git a/plugins/umlrt/core/org.eclipse.papyrusrt.umlrt.core/src/org/eclipse/papyrusrt/umlrt/core/types/advice/MessageSetEditHelperAdvice.java b/plugins/umlrt/core/org.eclipse.papyrusrt.umlrt.core/src/org/eclipse/papyrusrt/umlrt/core/types/advice/MessageSetEditHelperAdvice.java
index d73462d..5ab7982 100644
--- a/plugins/umlrt/core/org.eclipse.papyrusrt.umlrt.core/src/org/eclipse/papyrusrt/umlrt/core/types/advice/MessageSetEditHelperAdvice.java
+++ b/plugins/umlrt/core/org.eclipse.papyrusrt.umlrt.core/src/org/eclipse/papyrusrt/umlrt/core/types/advice/MessageSetEditHelperAdvice.java
@@ -9,21 +9,19 @@
  * Contributors: 
  *   Onder Gurcan <onder.gurcan@cea.fr> - Initial API and implementation
  *   Celine Janssens (ALL4TEC) celine.janssens@all4tec.net - Bug 476126
- *   Christian W. Damus - bug 467545
+ *   Christian W. Damus - bugs 467545, 512666
  *
  *****************************************************************************/
 
 package org.eclipse.papyrusrt.umlrt.core.types.advice;
 
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
 import org.eclipse.emf.common.util.EList;
-import org.eclipse.emf.edit.command.DeleteCommand;
 import org.eclipse.emf.transaction.TransactionalEditingDomain;
 import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
 import org.eclipse.gmf.runtime.common.core.command.ICommand;
@@ -33,11 +31,9 @@
 import org.eclipse.gmf.runtime.emf.type.core.commands.MoveElementsCommand;
 import org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice;
 import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
-import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest;
 import org.eclipse.gmf.runtime.emf.type.core.requests.IEditCommandRequest;
 import org.eclipse.gmf.runtime.emf.type.core.requests.MoveRequest;
 import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest;
-import org.eclipse.papyrus.commands.wrappers.EMFtoGMFCommandWrapper;
 import org.eclipse.papyrus.infra.core.services.ServiceException;
 import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
 import org.eclipse.papyrus.infra.services.edit.service.ElementEditServiceUtils;
@@ -80,24 +76,6 @@
 		return result;
 	}
 
-	@Override
-	protected ICommand getBeforeDestroyElementCommand(DestroyElementRequest request) {
-		ICommand command = null;
-		if (request.getElementToDestroy() instanceof Operation) {
-			Operation destroyOperation = (Operation) request.getElementToDestroy();
-			CallEvent relatedCallEvent = getRelatedCallEvent(destroyOperation.getNearestPackage(), destroyOperation);
-			if (null != relatedCallEvent) {
-				command = getDeletionCallEventCommand(relatedCallEvent);
-			}
-		}
-
-		if (null == command) {
-			command = super.getBeforeDestroyElementCommand(request);
-		}
-
-		return command;
-	}
-
 	/**
 	 * {@inheritDoc}
 	 */
@@ -241,43 +219,6 @@
 	}
 
 	/**
-	 * Get the Call Event deletion command
-	 * 
-	 * @param callEvent
-	 *            The call Event to delete
-	 * @return The Command to delete CallEvent
-	 */
-	private ICommand getDeletionCallEventCommand(CallEvent callEvent) {
-		ICommand command = null;
-
-		try {
-
-			TransactionalEditingDomain domain = ServiceUtilsForEObject.getInstance()
-					.getTransactionalEditingDomain(callEvent);
-
-			DeleteCommand EMFcommand = new DeleteCommand(domain, Collections.singletonList(callEvent));
-			command = EMFtoGMFCommandWrapper.wrap(EMFcommand);
-
-		} catch (ServiceException e) {
-			Activator.log.error(e);
-		}
-		return command;
-	}
-
-	/**
-	 * Get the Message List before the Modification
-	 * 
-	 * @param messageSet
-	 *            The messageSet containing the Message List
-	 * @return
-	 */
-	protected EList<Operation> getOldMessageList(Interface messageSet) {
-		EList<Operation> messageList = messageSet.getOwnedOperations();
-		return messageList;
-
-	}
-
-	/**
 	 * Get the command that generate a Call Event
 	 * 
 	 * @param targetClassifier
@@ -340,7 +281,7 @@
 	 *            Operation of the Call Event that is Related to.
 	 * @return The Associated Call Event.
 	 */
-	protected CallEvent getRelatedCallEvent(final Object container, final Operation operation) {
+	protected static CallEvent getRelatedCallEvent(final Object container, final Operation operation) {
 		CallEvent callEvent = null;
 		if (container instanceof org.eclipse.uml2.uml.Package) {
 			// List all the children of the Container
diff --git a/plugins/umlrt/core/org.eclipse.papyrusrt.umlrt.core/src/org/eclipse/papyrusrt/umlrt/core/types/advice/OperationAsMessageEditHelperAdvice.java b/plugins/umlrt/core/org.eclipse.papyrusrt.umlrt.core/src/org/eclipse/papyrusrt/umlrt/core/types/advice/OperationAsMessageEditHelperAdvice.java
index da55945..7c4eed1 100644
--- a/plugins/umlrt/core/org.eclipse.papyrusrt.umlrt.core/src/org/eclipse/papyrusrt/umlrt/core/types/advice/OperationAsMessageEditHelperAdvice.java
+++ b/plugins/umlrt/core/org.eclipse.papyrusrt.umlrt.core/src/org/eclipse/papyrusrt/umlrt/core/types/advice/OperationAsMessageEditHelperAdvice.java
@@ -8,12 +8,14 @@
  *
  * Contributors:
  *   Onder Gurcan <onder.gurcan@cea.fr> - Initial API and implementation
- *   Christian W. Damus - bug 507282
+ *   Christian W. Damus - bugs 507282, 512666
  *
  *****************************************************************************/
 
 package org.eclipse.papyrusrt.umlrt.core.types.advice;
 
+import static org.eclipse.papyrusrt.umlrt.core.types.advice.MessageSetEditHelperAdvice.getRelatedCallEvent;
+
 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -26,6 +28,7 @@
 import org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice;
 import org.eclipse.gmf.runtime.emf.type.core.requests.ConfigureRequest;
 import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
+import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyDependentsRequest;
 import org.eclipse.gmf.runtime.emf.type.core.requests.IEditCommandRequest;
 import org.eclipse.papyrus.infra.services.edit.service.ElementEditServiceUtils;
 import org.eclipse.papyrus.infra.services.edit.service.IElementEditService;
@@ -185,4 +188,23 @@
 			}
 		};
 	}
+
+	@Override
+	protected ICommand getBeforeDestroyDependentsCommand(DestroyDependentsRequest request) {
+		ICommand result = super.getBeforeDestroyDependentsCommand(request);
+
+		if (request.getElementToDestroy() instanceof Operation) {
+			Operation operation = (Operation) request.getElementToDestroy();
+			CallEvent relatedCallEvent = getRelatedCallEvent(operation.getNearestPackage(), operation);
+
+			if (relatedCallEvent != null) {
+				ICommand command = request.getDestroyDependentCommand(relatedCallEvent);
+				if (command != null) {
+					result = (result == null) ? command : result.compose(command);
+				}
+			}
+		}
+
+		return result;
+	}
 }
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolImpl.java
index ef5a2ab..b55e655 100644
--- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolImpl.java
+++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolImpl.java
@@ -752,9 +752,12 @@
 	}
 
 	Stream<Interface> messageSets() {
-		return toUML().getNearestPackage().getOwnedTypes().stream()
-				.filter(Interface.class::isInstance).map(Interface.class::cast)
-				.filter(UMLRTProtocolImpl::isRTMessageSet);
+		Package container = toUML().getNearestPackage();
+		return (container == null)
+				? Stream.empty()
+				: container.getOwnedTypes().stream()
+						.filter(Interface.class::isInstance).map(Interface.class::cast)
+						.filter(UMLRTProtocolImpl::isRTMessageSet);
 	}
 
 	Optional<Interface> getMessageSet(RTMessageKind kind) {
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolFacadeTest.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolFacadeTest.java
index 3437b3b..f133543 100644
--- a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolFacadeTest.java
+++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolFacadeTest.java
@@ -16,8 +16,10 @@
 import static java.util.stream.Collectors.toList;
 import static org.eclipse.papyrusrt.umlrt.uml.tests.util.UMLMatchers.named;
 import static org.eclipse.papyrusrt.umlrt.uml.tests.util.UMLMatchers.redefines;
+import static org.hamcrest.CoreMatchers.anything;
 import static org.hamcrest.CoreMatchers.hasItem;
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.CoreMatchers.sameInstance;
@@ -568,6 +570,24 @@
 		assertThat(wildcard.getOwner(), is(newProtocol.toUML().getNearestPackage()));
 	}
 
+	/**
+	 * Check that attempts to access the façade of a deleted protocol, as in
+	 * the Properties View UI, do not cause exceptions.
+	 */
+	@Test
+	public void deletedProtocolMessageSets_bug512666() {
+		UMLRTProtocol protocol1 = getProtocol("Protocol1");
+		UMLRTProtocol protocol2 = getProtocol("Protocol2");
+
+		protocol2.setSuperProtocol(protocol1);
+
+		// Simulate destruction in the UI, which completely disaggregates the tree
+		fixture.destroy(protocol2.toUML().getNearestPackage());
+
+		// Trying to access the message-sets should not throw
+		assertThat(protocol2.getExcludedElements(), not(hasItem(anything())));
+	}
+
 	//
 	// Test framework
 	//
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/util/ModelFixture.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/util/ModelFixture.java
index 11e42fb..3a52e83 100644
--- a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/util/ModelFixture.java
+++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/util/ModelFixture.java
@@ -183,6 +183,21 @@
 		return result;
 	}
 
+	/**
+	 * Simulates a GMF-style destruction of an {@code element}, including complete
+	 * disaggregation of its subtree.
+	 * 
+	 * @param element
+	 *            an element to "destroy"
+	 */
+	public void destroy(Element element) {
+		element.destroy();
+
+		for (Element next : element.allOwnedElements()) {
+			EcoreUtil.remove(next);
+		}
+	}
+
 	Predicate<EClass> canExtend(Class<?> umlMetaclass) {
 		return eClass -> eClass.getEAllReferences().stream()
 				.filter(r -> r.getName().startsWith("base_"))