blob: 0e9f60fae057a6717228b3a673f124427a305ad2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2019 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 v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Chalmers | University of Gothenburg and rt-labs - initial API and implementation and/or initial documentation
* Chalmers | University of Gothenburg - additional features, updated API
*******************************************************************************/
package org.eclipse.capra.ui.plantuml;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
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.TracePersistenceAdapter;
import org.eclipse.capra.core.handlers.IArtifactHandler;
import org.eclipse.capra.core.helpers.ArtifactHelper;
import org.eclipse.capra.core.helpers.EMFHelper;
import org.eclipse.capra.core.helpers.ExtensionPointHelper;
import org.eclipse.capra.generic.artifactmodel.ArtifactWrapper;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import com.google.common.base.Strings;
/**
* Helper class for generating PlantUML diagrams from a collection of
* {@link Connection}
*
* @author Anthony Anjorin, Salome Maro
*/
public class Connections {
private static final String CHARACTERS_TO_BE_REMOVED = "[\", \']";
private List<Connection> connections;
private EObject origin;
private Set<EObject> allObjects;
private Map<EObject, String> object2Id;
private Map<String, String> id2Label;
private Map<String, String> id2Location;
Connections(List<Connection> connections, List<EObject> selectedObjects) {
this.connections = connections;
origin = selectedObjects.get(0);
allObjects = new LinkedHashSet<>();
allObjects.addAll(selectedObjects);
connections.forEach(c -> allObjects.addAll(c.getTargets()));
object2Id = new LinkedHashMap<>();
int i = 0;
for (EObject o : allObjects) {
object2Id.put(o, "o" + i++);
}
id2Label = new LinkedHashMap<>();
allObjects.forEach(o -> {
String id = object2Id.get(o);
id2Label.put(id, getArtifactLabel(o));
});
id2Location = new LinkedHashMap<>();
allObjects.forEach(o -> {
String id = object2Id.get(o);
id2Location.put(id, getArtifactLocation(o));
});
}
public String originLabel() {
return id2Label.get(object2Id.get(origin));
}
public String originLocation() {
return id2Location.get(object2Id.get(origin));
}
public boolean originHasLocation() {
return !Strings.isNullOrEmpty(id2Location.get(object2Id.get(origin)));
}
public String originId() {
return object2Id.get(origin);
}
public Collection<String> objectIdsWithoutOrigin() {
Collection<String> all = new ArrayList<>();
all.addAll(object2Id.values());
all.remove(originId());
return all;
}
public String label(String id) {
return id2Label.get(id);
}
public String location(String id) {
return id2Location.get(id);
}
public boolean hasLocation(String id) {
return !Strings.isNullOrEmpty(id2Location.get(id));
}
public List<String> arrows() {
Set<String> arrows = new HashSet<>();
connections.forEach(c -> {
c.getTargets().forEach(trg -> {
if (!trg.equals(c.getOrigin())) {
arrows.add(object2Id.get(c.getOrigin()) + "--" + object2Id.get(trg) + ":"
+ EMFHelper.getIdentifier(c.getTlink()));
}
});
});
return arrows.stream().collect(Collectors.toList());
}
/**
* The method gets the label of the element to be used for display in the
* plant UML graph view and matrix view
*
* @param object
* The object for which the label is needed. This can be an EMF
* original representation or an artifact wrapper if the original
* object was not an EMF element
* @return The label to be displayed
*/
public static String getArtifactLabel(EObject object) {
String artifactLabel = null;
ArtifactMetaModelAdapter artifactMetaModelAdapter = ExtensionPointHelper.getArtifactWrapperMetaModelAdapter()
.get();
ResourceSet resourceSet = new ResourceSetImpl();
TracePersistenceAdapter persistenceAdapter = ExtensionPointHelper.getTracePersistenceAdapter().get();
EObject artifactModel = persistenceAdapter.getArtifactWrappers(resourceSet);
ArtifactHelper artifactHelper = new ArtifactHelper(artifactModel);
// assume object is and artifact wrapper and get its handler
IArtifactHandler<Object> handler = (IArtifactHandler<Object>) artifactMetaModelAdapter
.getArtifactHandlerInstance(object);
if (handler == null) {
// object is not an artifact handler
handler = (IArtifactHandler<Object>) artifactHelper.getHandler(object).orElse(null);
}
if ((handler != null)) {
Object originalObject = handler.resolveWrapper(object);
if (originalObject != null) {
artifactLabel = handler.withCastedHandler(originalObject, (h, o) -> h.getDisplayName(o))
.orElseThrow(IllegalArgumentException::new);
} else { // original object cannot be resolved
// therefore use the wrapper name
String label = EMFHelper.getIdentifier(object);
artifactLabel = label.substring(0, label.indexOf(':'));
}
} else {
artifactLabel = EMFHelper.getIdentifier(object);
}
// remove unwanted characters like ", '
if (artifactLabel != null) {
return artifactLabel.replaceAll(CHARACTERS_TO_BE_REMOVED, " ");
} else {
// This can happen if the trace model contains elements for which
// the artifact handler is not available.
// While this should not happen in a user installation, it is not
// uncommon during testing.
return "Unknown (no fitting artifact handler found)";
}
}
/**
* Retrieves the location of the given object in the workspace, resolving
* artifact wrappers as necessary.
* <p>
* This method relies on the correct setting of the {@code URI} attribute of
* the corresponding {@link ArtifactWrapper}. The URI should be recognisable
* by the platform to ensure that the correct editor is opened.
*
* @param object
* the {@code EObject} (or {@code ArtifactWrapper}) to get the
* link for
* @return a platform URI that can be used to resolve the object or
* {@code null} if none can be found
*/
public static String getArtifactLocation(EObject object) {
String artifactLink = null;
if (object instanceof ArtifactWrapper) {
ArtifactWrapper wrapper = (ArtifactWrapper) object;
artifactLink = wrapper.getUri();
} else {
try {
artifactLink = EcoreUtil.getURI(object).toPlatformString(false);
} catch (IllegalArgumentException ex) {
// Deliberately do nothing
}
}
if (!Strings.isNullOrEmpty(artifactLink) && artifactLink.startsWith("/")) {
artifactLink = "platform:/resource" + artifactLink;
}
return artifactLink;
}
}