Bug 517292 - [Feature] Prevent the creation of trace links that already exists

This is done by first creating a Connection that represents a trace link to be
created and comparing this to existing connections in the trace model.
In the current implementation, Connection A is equal to Connection B
if it contains the same elements (origin and targets) irrespective of
the order and has the same trace link type.

Change-Id: Iefcc574a8b19138828e020ba800c660176bbc640
diff --git a/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/adapters/Connection.java b/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/adapters/Connection.java
index 7c4e604..1c16ece 100644
--- a/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/adapters/Connection.java
+++ b/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/adapters/Connection.java
@@ -10,8 +10,11 @@
  *******************************************************************************/
 package org.eclipse.capra.core.adapters;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
+import org.eclipse.capra.core.helpers.EMFHelper;
 import org.eclipse.emf.ecore.EObject;
 
 /**
@@ -43,4 +46,37 @@
 	public EObject getTlink() {
 		return tlink;
 	}
+
+	@Override
+	public boolean equals(Object object) {
+		if (object == null) {
+			return false;
+		}
+		if (!(object instanceof Connection)) {
+			return false;
+		}
+		if (object == this) {
+			return true;
+		}
+		Connection connection = (Connection) object;
+
+		List<EObject> allFirstElements = new ArrayList<>(this.getTargets());
+		allFirstElements.add(this.getOrigin());
+
+		List<EObject> allSecondElements = new ArrayList<>(connection.getTargets());
+		allSecondElements.add(connection.getOrigin());
+
+		String firstTraceType = EMFHelper.getIdentifier(this.getTlink().eClass());
+		String secondTracetype = EMFHelper.getIdentifier(connection.getTlink().eClass());
+		if (!(firstTraceType.equals(secondTracetype))) {
+			return false;
+		}
+
+		List<String> firstElementsIds = allFirstElements.stream().map(e -> EMFHelper.getIdentifier(e))
+				.collect(Collectors.toList());
+		List<String> secondElementsIds = allSecondElements.stream().map(e -> EMFHelper.getIdentifier(e))
+				.collect(Collectors.toList());
+		return firstElementsIds.containsAll(secondElementsIds);
+	}
+
 }
diff --git a/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/adapters/TraceMetaModelAdapter.java b/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/adapters/TraceMetaModelAdapter.java
index 4a26093..2bfe5ef 100644
--- a/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/adapters/TraceMetaModelAdapter.java
+++ b/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/adapters/TraceMetaModelAdapter.java
@@ -57,7 +57,7 @@
 	 *            returned.
 	 * @param selection
 	 *            Objects to create the trace for
-	 * @return root of trace model that now contains the newly created trace
+	 * @return the trace link that has just been created
 	 */
 	EObject createTrace(EClass traceType, EObject traceModel, List<EObject> selection);
 
diff --git a/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/helpers/TraceHelper.java b/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/helpers/TraceHelper.java
index bf41ffb..b37ee24 100644
--- a/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/helpers/TraceHelper.java
+++ b/bundles/org.eclipse.capra.core/src/org/eclipse/capra/core/helpers/TraceHelper.java
@@ -23,6 +23,7 @@
 import org.eclipse.capra.core.handlers.IArtifactHandler;
 import org.eclipse.emf.ecore.EClass;
 import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
 
 /**
  * Helper class for creating traces
@@ -45,9 +46,10 @@
 	 *
 	 * @param wrappers
 	 * @param traceType
+	 * @return the trace link that has been created
 	 */
-	public void createTrace(List<EObject> wrappers, EClass traceType) {
-		traceAdapter.createTrace(traceType, traceModel, wrappers);
+	public EObject createTrace(List<EObject> wrappers, EClass traceType) {
+		return traceAdapter.createTrace(traceType, traceModel, wrappers);
 	}
 
 	/**
@@ -102,4 +104,35 @@
 		
 	}
 
+	/**
+	 * Checks if a trace link of a certain type containing a certain selection
+	 * already exists in the trace model.
+	 * 
+	 * @param selection
+	 *            the selected elements
+	 * @param traceType
+	 *            the type of trace link
+	 * @param traceModel
+	 *            the trace model to be checked
+	 * @return true if the link exists
+	 */
+
+	public boolean traceExists(List<EObject> selection, EClass traceType, EObject traceModel) {
+		TraceMetaModelAdapter traceAdapter = ExtensionPointHelper.getTraceMetamodelAdapter().get();
+		// create a connection
+		List<EObject> allElements = new ArrayList<>(selection);
+		EObject source = allElements.get(0);
+		allElements.remove(0);
+		List<EObject> targets = allElements;
+
+		// create temporary trace model with a temporary trace link
+		EObject tempTraceModel = ExtensionPointHelper.getTracePersistenceAdapter().get()
+				.getTraceModel(new ResourceSetImpl());
+		EObject tempTlink = traceAdapter.createTrace(traceType, tempTraceModel, selection);
+
+		Connection connection = new Connection(source, targets, tempTlink);
+
+		return traceAdapter.getAllTraceLinks(traceModel).stream().anyMatch(c -> c.equals(connection));
+	}
+
 }
diff --git a/bundles/org.eclipse.capra.generic.tracemodels/src/org/eclipse/capra/generic/tracemodels/GenericMetaModelAdapter.java b/bundles/org.eclipse.capra.generic.tracemodels/src/org/eclipse/capra/generic/tracemodels/GenericMetaModelAdapter.java
index aa2b755..26d4cbc 100644
--- a/bundles/org.eclipse.capra.generic.tracemodels/src/org/eclipse/capra/generic/tracemodels/GenericMetaModelAdapter.java
+++ b/bundles/org.eclipse.capra.generic.tracemodels/src/org/eclipse/capra/generic/tracemodels/GenericMetaModelAdapter.java
@@ -83,7 +83,7 @@
 		}
 		relatedToTrace.setName(name.toString());
 		tm.getTraces().add(relatedToTrace);
-		return tm;
+		return relatedToTrace;
 	}
 
 	@Override
@@ -177,9 +177,11 @@
 		List<Connection> allLinks = new ArrayList<>();
 
 		for (RelatedTo trace : model.getTraces()) {
-			EObject origin = trace.getItem().get(0);
-			trace.getItem().remove(0);
-			allLinks.add(new Connection(origin, trace.getItem(), trace));
+			List<EObject> allItems = new ArrayList<>();
+			allItems.addAll(trace.getItem());
+			EObject origin = allItems.get(0);
+			allItems.remove(0);
+			allLinks.add(new Connection(origin, allItems, trace));
 		}
 		return allLinks;
 	}
diff --git a/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/handlers/TraceCreationHandler.java b/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/handlers/TraceCreationHandler.java
index 0f2a467..a7d60e1 100644
--- a/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/handlers/TraceCreationHandler.java
+++ b/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/handlers/TraceCreationHandler.java
@@ -30,6 +30,7 @@
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.resource.ResourceSet;
 import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.window.Window;
 import org.eclipse.ui.IWorkbenchWindow;
@@ -70,9 +71,15 @@
 
 		// Create trace
 		if (chosenType.isPresent()) {
+			// check if the connection already exists
+			if (traceHelper.traceExists(wrappers, chosenType.get(), traceModel)) {
+				MessageDialog.openInformation(window.getShell(), "Capra Information",
+						"The trace link you want to create already exists and will therefore not be created");
+			} else {
 			traceHelper.createTrace(wrappers, chosenType.get());
 			persistenceAdapter.saveTracesAndArtifacts(traceModel, artifactModel);
-			traceHelper.annotateTrace(wrappers);
+				traceHelper.annotateTrace(wrappers);
+			}
 		}
 	}
 
@@ -95,4 +102,5 @@
 
 		return Optional.empty();
 	}
+
 }