refactor TraceCreationHandler into ui/non-ui parts

Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=508876
Change-Id: I36433b34510551d7b1210d4262ccf5c27bc1b3c7
diff --git a/org.eclipse.capra.core/src/org/eclipse/capra/core/helpers/TraceCreationHelper.java b/org.eclipse.capra.core/src/org/eclipse/capra/core/helpers/TraceCreationHelper.java
new file mode 100644
index 0000000..61c1627
--- /dev/null
+++ b/org.eclipse.capra.core/src/org/eclipse/capra/core/helpers/TraceCreationHelper.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Chalmers | University of Gothenburg, rt-labs 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:
+ *    Chalmers | University of Gothenburg and rt-labs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+package org.eclipse.capra.core.helpers;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.eclipse.capra.core.adapters.ArtifactMetaModelAdapter;
+import org.eclipse.capra.core.adapters.Connection;
+import org.eclipse.capra.core.adapters.TraceMetaModelAdapter;
+import org.eclipse.capra.core.handlers.IAnnotateArtifact;
+import org.eclipse.capra.core.handlers.IArtifactHandler;
+import org.eclipse.capra.core.handlers.PriorityHandler;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * Helper class for creating traces
+ */
+public class TraceCreationHelper {
+
+	private EObject traceModel;
+	private EObject artifactModel;
+	private TraceMetaModelAdapter traceAdapter = ExtensionPointHelper.getTraceMetamodelAdapter().get();
+	private ArtifactMetaModelAdapter artifactAdapter = ExtensionPointHelper.getArtifactWrapperMetaModelAdapter().get();
+	private Optional<PriorityHandler> priorityHandler = ExtensionPointHelper.getPriorityHandler();
+	private Collection<IArtifactHandler<Object>> handlers = ExtensionPointHelper.getArtifactHandlers();
+
+	/**
+	 * @param traceModel
+	 * @param artifactModel
+	 */
+	public TraceCreationHelper(EObject traceModel, EObject artifactModel) {
+		this.traceModel = traceModel;
+		this.artifactModel = artifactModel;
+	}
+
+	/**
+	 * Get a handler for the artifact
+	 * @param artifact
+	 * @return handler or null if no handler exists
+	 */
+	public IArtifactHandler<Object> getHandler(Object artifact) {
+		List<IArtifactHandler<Object>> availableHandlers = handlers
+				.stream()
+				.filter(h -> h.canHandleArtifact(artifact))
+				.collect(Collectors.toList());
+
+		// TODO: Could this be folded into the pipeline above?
+		if (availableHandlers.size() == 1) {
+			return availableHandlers.get(0);
+		} else if (availableHandlers.size() > 1 && priorityHandler.isPresent()) {
+			return priorityHandler.get().getSelectedHandler(availableHandlers, artifact);
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * Creates wrapper for artifact
+	 *
+	 * @param artifact
+	 * @return wrapper of null if no handler exists
+	 */
+	public EObject createWrapper(Object artifact) {
+		IArtifactHandler<Object> handler = getHandler(artifact);
+		if (handler == null) {
+			return null;
+		}
+		return handler.createWrapper(artifact, artifactModel);
+	}
+
+	/**
+	 * Creates wrappers for artifacts
+	 *
+	 * @param artifacts
+	 * @return List of wrappers
+	 */
+	public List<EObject> createWrappers(List<Object> artifacts) {
+		List<EObject> wrappers = artifacts
+				.stream()
+				.map(a -> createWrapper(a))
+				.collect(Collectors.toList());
+		return wrappers;
+	}
+
+	/**
+	 * Create a trace of the given traceType
+	 *
+	 * @param wrappers
+	 * @param traceType
+	 */
+	public void createTrace(List<EObject> wrappers, EClass traceType) {
+		traceAdapter.createTrace(traceType, traceModel, wrappers);
+	}
+
+	/**
+	 * Annotate artifacts represented by wrappers
+	 *
+	 * @param wrappers
+	 */
+	public void annotateTrace(List<EObject> wrappers) {
+		// Annotate if possible
+		for (EObject wrapper : wrappers) {
+			IArtifactHandler<Object> handler = artifactAdapter.getArtifactHandlerInstance(wrapper);
+			if (handler instanceof IAnnotateArtifact) {
+				IAnnotateArtifact h = (IAnnotateArtifact) handler;
+				try {
+					// Get unique connected artifacts, not including this element
+					// TODO: maybe add an adapter method for this?
+					Set<EObject> connectedElements = new HashSet<EObject>();
+					final StringBuilder annotation = new StringBuilder();
+					List<Connection> connections = traceAdapter.getConnectedElements(wrapper, traceModel);
+					connections.forEach(c -> {
+						c.getTargets().forEach(t -> {
+							if (t != wrapper) {
+								connectedElements.add(t);
+							}
+						});
+					});
+
+					// Build annotation string
+					connectedElements.forEach(e -> {
+						if (annotation.length() > 0) {
+							annotation.append(", ");
+						}
+						String name = artifactAdapter.getArtifactName(e);
+						annotation.append(name);
+					});
+
+					h.annotateArtifact(wrapper, annotation.toString());
+				} catch (Exception e) {
+					// Ignore
+				}
+			}
+		}
+	}
+
+}
diff --git a/org.eclipse.capra.ui/src/org/eclipse/capra/ui/handlers/TraceCreationHandler.java b/org.eclipse.capra.ui/src/org/eclipse/capra/ui/handlers/TraceCreationHandler.java
index fb86b82..ae75562 100644
--- a/org.eclipse.capra.ui/src/org/eclipse/capra/ui/handlers/TraceCreationHandler.java
+++ b/org.eclipse.capra.ui/src/org/eclipse/capra/ui/handlers/TraceCreationHandler.java
@@ -11,22 +11,16 @@
 package org.eclipse.capra.ui.handlers;
 
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
-import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.stream.Collectors;
 
-import org.eclipse.capra.core.adapters.ArtifactMetaModelAdapter;
-import org.eclipse.capra.core.adapters.Connection;
 import org.eclipse.capra.core.adapters.TraceMetaModelAdapter;
 import org.eclipse.capra.core.adapters.TracePersistenceAdapter;
-import org.eclipse.capra.core.handlers.IAnnotateArtifact;
-import org.eclipse.capra.core.handlers.IArtifactHandler;
-import org.eclipse.capra.core.handlers.PriorityHandler;
 import org.eclipse.capra.core.helpers.EMFHelper;
 import org.eclipse.capra.core.helpers.ExtensionPointHelper;
+import org.eclipse.capra.core.helpers.TraceCreationHelper;
 import org.eclipse.capra.ui.views.SelectionView;
 import org.eclipse.core.commands.AbstractHandler;
 import org.eclipse.core.commands.ExecutionEvent;
@@ -35,7 +29,6 @@
 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;
@@ -53,7 +46,7 @@
 
 	public void createTrace(IWorkbenchWindow window,
 			BiFunction<Collection<EClass>, List<EObject>, Optional<EClass>> chooseTraceType) {
-		List<Object> selection = SelectionView.getOpenedView().getSelection();
+		List<Object> artifacts = SelectionView.getOpenedView().getSelection();
 
 		TraceMetaModelAdapter traceAdapter = ExtensionPointHelper.getTraceMetamodelAdapter().get();
 		TracePersistenceAdapter persistenceAdapter = ExtensionPointHelper.getTracePersistenceAdapter().get();
@@ -64,87 +57,25 @@
 		// add artifact model to resource set
 		EObject artifactModel = persistenceAdapter.getArtifactWrappers(resourceSet);
 
-		Collection<IArtifactHandler<Object>> artifactHandlers = ExtensionPointHelper.getArtifactHandlers();
+		TraceCreationHelper helper = new TraceCreationHelper(traceModel, artifactModel);
 
-		List<EObject> selectionAsEObjects = mapSelectionToEObjects(window, artifactModel, artifactHandlers, selection);
+		// Create the artifact wrappers
+		List<EObject> wrappers = helper.createWrappers(artifacts);
 
-		Collection<EClass> traceTypes = traceAdapter.getAvailableTraceTypes(selectionAsEObjects);
-		Optional<EClass> chosenType = chooseTraceType.apply(traceTypes, selectionAsEObjects);
+		// Get the type of trace to be created
+		Collection<EClass> traceTypes = traceAdapter.getAvailableTraceTypes(wrappers);
+		Optional<EClass> chosenType = chooseTraceType.apply(traceTypes, wrappers);
 
+		// Create trace
 		if (chosenType.isPresent()) {
-			EObject root = traceAdapter.createTrace(chosenType.get(), traceModel, selectionAsEObjects);
-			persistenceAdapter.saveTracesAndArtifacts(root, artifactModel);
-			annotateTrace(traceAdapter, traceModel, selectionAsEObjects);
+			helper.createTrace(wrappers, chosenType.get());
+			persistenceAdapter.saveTracesAndArtifacts(traceModel, artifactModel);
+			helper.annotateTrace(wrappers);
 		}
 	}
 
-	private void annotateTrace(TraceMetaModelAdapter traceAdapter, EObject traceModel,
-			List<EObject> artifacts) {
-		ArtifactMetaModelAdapter adapter = ExtensionPointHelper.getArtifactWrapperMetaModelAdapter().get();
-
-		// Annotate if possible
-		for (EObject artifact : artifacts) {
-			IArtifactHandler<Object> handler = adapter.getArtifactHandlerInstance(artifact);
-			if (handler instanceof IAnnotateArtifact) {
-				IAnnotateArtifact h = (IAnnotateArtifact) handler;
-				try {
-					// Get unique connected artifacts, not including this element
-					// TODO: maybe add an adapter method for this?
-					Set<EObject> connectedElements = new HashSet<EObject>();
-					final StringBuilder annotation = new StringBuilder();
-					List<Connection> connections = traceAdapter.getConnectedElements(artifact, traceModel);
-					connections.forEach(c -> {
-						c.getTargets().forEach(t -> {
-							if (t != artifact) {
-								connectedElements.add(t);
-							}
-						});
-					});
-
-					// Build annotation string
-					connectedElements.forEach(e -> {
-						if (annotation.length() > 0) {
-							annotation.append(", ");
-						}
-						String name = adapter.getArtifactName(e);
-						annotation.append(name);
-					});
-
-					h.annotateArtifact(artifact, annotation.toString());
-				} catch (Exception e) {
-					// Ignore
-				}
-			}
-		}
-	}
-
-	private List<EObject> mapSelectionToEObjects(IWorkbenchWindow window, EObject artifactModel,
-			Collection<IArtifactHandler<Object>> artifactHandlers, List<Object> selection) {
-		return selection.stream().map(sel -> convertToEObject(window, sel, artifactHandlers, artifactModel))
-				.filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
-	}
-
-	private Optional<EObject> convertToEObject(IWorkbenchWindow window, Object sel,
-			Collection<IArtifactHandler<Object>> artifactHandlers, EObject artifactModel) {
-		List<IArtifactHandler<Object>> availableHandlers = artifactHandlers.stream()
-				.filter(handler -> handler.canHandleArtifact(sel)).collect(Collectors.toList());
-		Optional<PriorityHandler> priorityHandler = ExtensionPointHelper.getPriorityHandler();
-
-		if (availableHandlers.size() == 1) {
-			return Optional.of(availableHandlers.get(0).createWrapper(sel, artifactModel));
-		} else if (availableHandlers.size() > 1 && priorityHandler.isPresent()) {
-			IArtifactHandler<Object> selectedHandler = priorityHandler.get().getSelectedHandler(availableHandlers, sel);
-			return Optional.of(selectedHandler.createWrapper(sel, artifactModel));
-		} else {
-			MessageDialog.openWarning(window.getShell(), "No handler for selected item",
-					"There is no handler for " + sel + " so it will be ignored.");
-			return Optional.empty();
-		}
-
-	}
-
 	private Optional<EClass> getTraceTypeToCreate(IWorkbenchWindow window, Collection<EClass> traceTypes,
-			List<EObject> selectionAsEObjects) {
+			List<EObject> wrappers) {
 		ElementListSelectionDialog dialog = new ElementListSelectionDialog(window.getShell(), new LabelProvider() {
 			@Override
 			public String getText(Object element) {
@@ -155,7 +86,7 @@
 		dialog.setTitle("Select the trace type you want to create");
 		dialog.setElements(traceTypes.toArray());
 		dialog.setMessage("Selection: "
-				+ selectionAsEObjects.stream().map(EMFHelper::getIdentifier).collect(Collectors.toList()));
+				+ wrappers.stream().map(EMFHelper::getIdentifier).collect(Collectors.toList()));
 
 		if (dialog.open() == Window.OK) {
 			return Optional.of((EClass) dialog.getFirstResult());