blob: a9fb19ce71edf2eee4c4fcf68d677cdf6df1d028 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2021 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.core.helpers;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
/**
* Contains methods to work with {@link EObject} instances encountered when
* handling EMF models.
*/
public class EMFHelper {
private EMFHelper() {
super();
}
/**
* Builds an identifier String for the given EObject. This identifier starts
* with
* <ul>
* <li>the attribute of the EObject as a String, if the EObject does only have
* one attribute.</li>
* <li>the attribute called 'name' of the EObject, if it has such an
* attribute</li>
* <li>any attribute of the EObject, but String attributes are preferred</li>
* </ul>
* The identifier ends with " : " followed by the type of the EObject. <br>
* Example: A Node with the name "foo" will result in "foo : Node" <br>
* If the EObject does not have any attributes or all attributes have the value
* null, this function will only return the type of the EObject.
*/
public static String getIdentifier(final EObject eObject) {
if (eObject == null) {
return "<null>";
}
if (eObject.eClass() == null) {
return eObject.toString();
}
boolean success = false;
List<EAttribute> attributes = eObject.eClass().getEAllAttributes();
StringBuilder identifier = new StringBuilder();
success = tryGetNameAttribute(eObject, identifier);
// We didn't find a name. Try finding something else that we can use.
if (!success) {
success = tryGetAnyAttribute(eObject, attributes, identifier);
}
if (success) {
identifier.append(" : ");
}
identifier.append(eObject.eClass().getName());
return identifier.toString();
}
/**
* Tries to retrieve a {@code String} representation of the provided
* {@code EAttribute} for the provided {@code EObject}. If the attribute is
* {@code null}, it is not a valid attribute of the given {@code EObject} or the
* value of the attribute is {@code} null, this method will return {@code false}
* and the provided {@code StringBuilder} will not be altered.
*
* @param builder {@code StringBuilder} to construct the String representation
* of the provided {@code EAttribute}. If this method returns
* {@code true}, this parameter has been changed, if it returns
* {@code false}, the {@code StringBuilder} is unaltered.
* @return indicates the success of this function and if the
* {@code StringBuilder} contains output.
*/
public static boolean tryGetAttribute(final EObject eObject, final EAttribute attribute, final StringBuilder name) {
boolean success = false;
if (attribute != null) {
try {
Object obj = eObject.eGet(attribute);
if (obj != null) {
name.append(obj.toString());
success = true;
}
} catch (IllegalArgumentException ex) {
// Deliberately do nothing.
// This can happen if the provided attribute is not an attribute of the eObject.
// In this case, we just want the method to return false, which it does if we
// just hold our feet still.
}
}
return success;
}
/**
* Tries to retrieve a String representation of the attribute "name" from the
* provided {@code EObject}.
*
* @param builder {@code StringBuilder} to construct the String representation
* of the {@code EObject}'s "name" attribute. If this function
* returns {@code true}, this parameter has been filled, if it
* returns {@code false}, the {@code StringBuilder} is unaltered.
* @return indicates the success of this function and if the
* {@code StringBuilder} contains output.
* @see #tryGetAttribute(EObject, EAttribute, StringBuilder)
*/
public static boolean tryGetNameAttribute(final EObject eObject, final StringBuilder builder) {
boolean success = false;
for (EAttribute attribute : eObject.eClass().getEAllAttributes()) {
if (attribute.getName().equals("name")) {
success = tryGetAttribute(eObject, attribute, builder);
}
}
return success;
}
/**
* Attempts to retrieve a {@code String} representation of any of the given
* attributes. For that purpose, it iterates over all attributes until it finds
* one which is not null and non-empty. It then adds the String representation
* of that attribute's value to the provided {@code StringBuilder} and returns
* {@code true}.
*
* @param builder {@code StringBuilder} to construct the String representation
* of the first non-null, non-empty attribute. If this function
* returns {@code true}, this parameter has been filled, if it
* returns {@code false}, the {@code StringBuilder} is unaltered.
* @return indicates the success of this function and if the
* {@code StringBuilder} contains output.
*/
public static boolean tryGetAnyAttribute(final EObject eObject, final List<EAttribute> attributes,
final StringBuilder name) {
boolean success = false;
String stringName = "";
for (EAttribute feature : attributes) {
Object obj = eObject.eGet(feature);
if (obj instanceof String) {
stringName = (String) obj;
} else if (obj != null) {
stringName = obj.toString();
}
if (stringName != null && !stringName.equals("null")) {
name.append(stringName);
success = true;
break;
}
}
return success;
}
/**
* Linearizes a tree to a list. The function checks if the provided parameter is
* of type {@link EObject} and linearizes only if that is the case. The root of
* the tree will always be the first element in the list.
*
* @param object the object to linearize
* @return a list of {@link EObject}s originally contained in the tree structure
* of the parameter or an empty list if the paramter was not an
* {@link EObject}
*/
public static List<EObject> linearize(Object object) {
ArrayList<EObject> elementList = new ArrayList<>();
if (object instanceof EObject) {
EObject root = (EObject) object;
elementList.add(root);
root.eAllContents().forEachRemaining(elementList::add);
}
return elementList;
}
/**
* Public API access for other classes to get the name attribute of an EObject
*
* @param eObject
* @return String
*/
public static String getNameAttribute(final EObject eObject) {
StringBuilder name = new StringBuilder();
tryGetNameAttribute(eObject, name);
return name.toString();
}
/**
* Compares to {@link EObject} instances based on their identifier using
* {@link EMFHelper#getIdentifier(EObject)}.
*
* @param first the first {@code EObject} to compare
* @param second the second {@code EObject} to compare
* @return {@code true} if the identifiers of the two instances are equal,
* {@code false} otherwise
*/
public static boolean hasSameIdentifier(EObject first, EObject second) {
return EMFHelper.getIdentifier(first).equals(EMFHelper.getIdentifier(second));
}
/**
* Checks if the given {@link EObject} is in the list of {@code EObject}s using
* {@link #hasSameIdentifier(EObject, EObject)}.
*
* @param list the list to check
* @param obj the object to check for
* @return {@code true} if {@code obj} is in {@code list}, {@code false}
* otherwise
*/
public static boolean isElementInList(List<EObject> list, EObject obj) {
for (EObject next : list) {
if (EMFHelper.hasSameIdentifier(obj, next)) {
return true;
}
}
return false;
}
}