/**
* Copyright (c) 2012-2016 Marsha Chechik, Alessio Di Sandro, Michalis Famelis,
* Rick Salay.
* 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:
* Alessio Di Sandro - Implementation.
*/
package edu.toronto.cs.se.mmint.mavo.library;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Stereotype;
import edu.toronto.cs.se.mmint.MMINTException;
import edu.toronto.cs.se.mmint.mavo.mavomid.MAVOModel;
import edu.toronto.cs.se.mmint.mavo.mavomid.MAVOModelElement;
import edu.toronto.cs.se.mmint.mavo.mavomid.MAVOModelElementReference;
import edu.toronto.cs.se.mavo.MAVOCollection;
import edu.toronto.cs.se.mavo.MAVOElement;
import edu.toronto.cs.se.mavo.MAVORoot;
import edu.toronto.cs.se.mmint.mid.Model;
import edu.toronto.cs.se.mmint.mid.ModelElement;
import edu.toronto.cs.se.mmint.mid.utils.FileUtils;
public class MAVOUtils {
public static final @NonNull String UML_MAVO_PROFILE = "MAVOProfile";
private static final @NonNull String UML_INC_STEREOTYPE = UML_MAVO_PROFILE + "::" + "inc";
private static final @NonNull String UML_MAY_STEREOTYPE = UML_MAVO_PROFILE + "::" + "may";
private static final @NonNull String UML_SET_STEREOTYPE = UML_MAVO_PROFILE + "::" + "set";
private static final @NonNull String UML_VAR_STEREOTYPE = UML_MAVO_PROFILE + "::" + "var";
public static final @NonNull Map<String, String> MAVO_UML_STEREOTYPE_EQUIVALENCE;
static {
MAVO_UML_STEREOTYPE_EQUIVALENCE = new HashMap<>();
MAVO_UML_STEREOTYPE_EQUIVALENCE.put("MAVORoot", "inc");
MAVO_UML_STEREOTYPE_EQUIVALENCE.put("MAVOElement", "may");
MAVO_UML_STEREOTYPE_EQUIVALENCE.put("MAVOElement", "set");
MAVO_UML_STEREOTYPE_EQUIVALENCE.put("MAVOElement", "var");
}
private static final String NAME_FEATURE = "name";
public static String getMAVORootLabel(MAVORoot rootMavoModelObj, boolean withParenthesis) {
String label = "";
if (rootMavoModelObj.isInc()) {
label =
(withParenthesis ? "(" : "") +
(rootMavoModelObj.isInc() ? "Inc" : "") +
(withParenthesis ? ")" : "");
}
return label;
}
public static String getMAVOElementLabel(MAVOElement mavoModelObj, boolean withParenthesis) {
String label = "";
boolean mavo = mavoModelObj.isMay() || mavoModelObj.isSet() || mavoModelObj.isVar();
if (mavo) {
String collectionsLabel = mavoModelObj.getCollections().stream()
.map(MAVOCollection::getFormulaVariable)
.collect(Collectors.joining(", "));
label =
(withParenthesis ? "(" : "") +
(mavoModelObj.isMay() ? "M" : "") +
(mavoModelObj.isSet() ? "S" : "") +
(mavoModelObj.isVar() ? "V" : "") +
(withParenthesis ? ")" : "") +
(collectionsLabel.equals("") ? "" : " [" + collectionsLabel + "]");
}
return label;
}
public static void setMAVORootLabel(MAVORoot rootMavoModelObj, String newLabel) {
// I-Inc are the only allowable combinations (plus empty string)
if (newLabel.trim().equals("I") || newLabel.trim().equals("Inc")) {
rootMavoModelObj.setInc(true);
}
else if (newLabel.trim().equals("")) {
rootMavoModelObj.setInc(false);
}
}
public static void setMAVOElementLabel(MAVOElement mavoModelObj, String newLabel) {
// M-S-V are the only allowable chars (plus empty string), and they can't appear more than once
boolean isMay = false, isSet = false, isVar = false;
for (char c : newLabel.replace(" ", "").toUpperCase().toCharArray()) {
switch (c) {
case 'M':
if (isMay) {
return;
}
isMay = true;
break;
case 'S':
if (isSet) {
return;
}
isSet = true;
break;
case 'V':
if (isVar) {
return;
}
isVar = true;
break;
default:
return;
}
}
mavoModelObj.setMay(isMay);
mavoModelObj.setSet(isSet);
mavoModelObj.setVar(isVar);
}
public static boolean isMAVOModel(EObject rootModelObj) {
// Ecore
if (rootModelObj instanceof MAVORoot) {
return true;
}
// UML
if (rootModelObj instanceof org.eclipse.uml2.uml.Model) {
return ((org.eclipse.uml2.uml.Model) rootModelObj).getAppliedProfile(UML_MAVO_PROFILE) != null;
}
return false;
}
public static boolean isMAVOElement(EObject modelObj) {
// Ecore
if (modelObj instanceof MAVOElement) {
return true;
}
// UML
if (modelObj instanceof NamedElement) {
NamedElement umlModelObj = (NamedElement) modelObj;
Stereotype stereotype = umlModelObj.getApplicableStereotype(UML_MAY_STEREOTYPE);
if (stereotype != null) {
return true;
}
}
return false;
}
public static boolean isMAVOModel(Model model) {
try {
return isMAVOModel(model.getEMFInstanceRoot());
}
catch (MMINTException e) {
MMINTException.print(IStatus.WARNING, "Can't get model root object, skipping MAVO evaluation", e);
return false;
}
}
public static boolean isMAVOElement(ModelElement modelElem) {
try {
return isMAVOElement(modelElem.getEMFInstanceObject());
}
catch (MMINTException e) {
MMINTException.print(IStatus.WARNING, "Can't get model object, skipping MAVO evaluation", e);
return false;
}
}
private static void initializeMAVOModel(MAVORoot rootModelObj, MAVOModel mavoModel) {
mavoModel.setInc(rootModelObj.isInc());
}
private static void initializeMAVOModel(org.eclipse.uml2.uml.Model rootUmlModelObj, MAVOModel mavoModel) {
Stereotype stereotype = rootUmlModelObj.getAppliedStereotype(UML_INC_STEREOTYPE);
if (stereotype != null) {
mavoModel.setInc(true);
}
}
public static void initializeMAVOModel(EObject rootModelObj, MAVOModel model) {
// Ecore
if (rootModelObj instanceof MAVORoot) {
initializeMAVOModel((MAVORoot) rootModelObj, model);
}
// UML
else if (rootModelObj instanceof org.eclipse.uml2.uml.Model) {
initializeMAVOModel((org.eclipse.uml2.uml.Model) rootModelObj, model);
}
}
private static void initializeMAVOModelElement(MAVOElement modelObj, MAVOModelElement mavoModelElem) {
mavoModelElem.setMay(modelObj.isMay());
mavoModelElem.setSet(modelObj.isSet());
mavoModelElem.setVar(modelObj.isVar());
mavoModelElem.setFormulaVariable(modelObj.getFormulaVariable());
}
private static void initializeMAVOModelElement(NamedElement umlModelObj, MAVOModelElement mavoModelElem) {
Stereotype stereotype = umlModelObj.getAppliedStereotype(UML_MAY_STEREOTYPE);
if (stereotype != null) {
mavoModelElem.setMay(true);
}
stereotype = umlModelObj.getAppliedStereotype(UML_SET_STEREOTYPE);
if (stereotype != null) {
mavoModelElem.setSet(true);
}
stereotype = umlModelObj.getAppliedStereotype(UML_VAR_STEREOTYPE);
if (stereotype != null) {
mavoModelElem.setVar(true);
}
mavoModelElem.setFormulaVariable(umlModelObj.getName().toLowerCase());
}
public static void initializeMAVOModelElement(EObject modelObj, MAVOModelElement mavoModelElem) {
// Ecore
if (modelObj instanceof MAVOElement) {
initializeMAVOModelElement((MAVOElement) modelObj, mavoModelElem);
}
// UML
else if (modelObj instanceof NamedElement) {
initializeMAVOModelElement((NamedElement) modelObj, mavoModelElem);
}
}
public static void initializeMAVOModelElementReference(EObject modelObj, MAVOModelElementReference mavoModelElemRef) {
initializeMAVOModelElement(modelObj, mavoModelElemRef.getObject());
}
public static void setInc(EObject rootModelObj, boolean inc) {
// Ecore
if (rootModelObj instanceof MAVORoot) {
((MAVORoot) rootModelObj).setInc(inc);
}
// UML
else if (rootModelObj instanceof org.eclipse.uml2.uml.Model) {
org.eclipse.uml2.uml.Model umlRootModelObj = (org.eclipse.uml2.uml.Model) rootModelObj;
Stereotype stereotype = umlRootModelObj.getApplicableStereotype(UML_INC_STEREOTYPE);
if (stereotype != null) {
if (inc && !umlRootModelObj.isStereotypeApplied(stereotype)) {
umlRootModelObj.applyStereotype(stereotype);
}
else if (!inc && umlRootModelObj.isStereotypeApplied(stereotype)) {
umlRootModelObj.unapplyStereotype(stereotype);
}
}
}
}
public static void setMay(EObject modelObj, boolean may) {
// Ecore
if (modelObj instanceof MAVOElement) {
((MAVOElement) modelObj).setMay(may);
}
// UML
else if (modelObj instanceof NamedElement) {
NamedElement umlModelObj = (NamedElement) modelObj;
Stereotype stereotype = umlModelObj.getApplicableStereotype(UML_MAY_STEREOTYPE);
if (stereotype != null) {
if (may && !umlModelObj.isStereotypeApplied(stereotype)) {
umlModelObj.applyStereotype(stereotype);
}
else if (!may && umlModelObj.isStereotypeApplied(stereotype)) {
umlModelObj.unapplyStereotype(stereotype);
}
}
}
}
public static void setSet(EObject modelObj, boolean set) {
// Ecore
if (modelObj instanceof MAVOElement) {
((MAVOElement) modelObj).setSet(set);
}
// UML
else if (modelObj instanceof NamedElement) {
NamedElement umlModelObj = (NamedElement) modelObj;
Stereotype stereotype = umlModelObj.getApplicableStereotype(UML_SET_STEREOTYPE);
if (stereotype != null) {
if (set && !umlModelObj.isStereotypeApplied(stereotype)) {
umlModelObj.applyStereotype(stereotype);
}
else if (!set && umlModelObj.isStereotypeApplied(stereotype)) {
umlModelObj.unapplyStereotype(stereotype);
}
}
}
}
public static void setVar(EObject modelObj, boolean var) {
// Ecore
if (modelObj instanceof MAVOElement) {
((MAVOElement) modelObj).setVar(var);
}
// UML
else if (modelObj instanceof NamedElement) {
NamedElement umlModelObj = (NamedElement) modelObj;
Stereotype stereotype = umlModelObj.getApplicableStereotype(UML_VAR_STEREOTYPE);
if (stereotype != null) {
if (var && !umlModelObj.isStereotypeApplied(stereotype)) {
umlModelObj.applyStereotype(stereotype);
}
else if (!var && umlModelObj.isStereotypeApplied(stereotype)) {
umlModelObj.unapplyStereotype(stereotype);
}
}
}
}
public static void copyMAVOElement(MAVOElement oldMAVOElement, MAVOElement newMAVOElement) {
newMAVOElement.setMay(oldMAVOElement.isMay());
newMAVOElement.setSet(oldMAVOElement.isSet());
newMAVOElement.setVar(oldMAVOElement.isVar());
newMAVOElement.setFormulaVariable(oldMAVOElement.getFormulaVariable());
}
public static Map<String, MAVOElement> createFormulaVars(Model mavoModel) throws Exception {
Map<String, MAVOElement> mavoModelObjs = new HashMap<>();
boolean modified = false;
MAVORoot mavoRootModelObj = (MAVORoot) mavoModel.getEMFInstanceRoot();
TreeIterator<EObject> iterator = mavoRootModelObj.eAllContents();
while (iterator.hasNext()) {
EObject modelObj = iterator.next();
if (!(modelObj instanceof MAVOElement)) {
continue;
}
MAVOElement mavoModelObj = (MAVOElement) modelObj;
if (mavoModelObj.getFormulaVariable() == null || mavoModelObj.getFormulaVariable().equals("")) {
EStructuralFeature nameFeature = mavoModelObj.eClass().getEStructuralFeature(NAME_FEATURE);
if (nameFeature != null) {
mavoModelObj.setFormulaVariable(((String) mavoModelObj.eGet(nameFeature)).replace(" ", ""));
modified = true;
}
}
mavoModelObjs.put(mavoModelObj.getFormulaVariable(), mavoModelObj);
}
// overwrite
if (modified) {
FileUtils.writeModelFile(mavoRootModelObj, mavoModel.getUri(), true);
}
return mavoModelObjs;
}
public static boolean isMayOnly(Map<String, MAVOElement> mavoModelObjs) {
return !mavoModelObjs.values().stream().anyMatch(mavoModelObj -> mavoModelObj.isSet() || mavoModelObj.isVar());
}
private static @NonNull Set<String> getVFormulaVars(@NonNull MAVORoot mavoModel, @NonNull MAVOElement mavoModelObj, boolean whichFormulaVars) {
Set<String> formulaVars = new HashSet<>();
EObject modelObjContainer = mavoModelObj.eContainer();
TreeIterator<EObject> iterator = mavoModel.eAllContents();
while (iterator.hasNext()) {
EObject otherModelObj = iterator.next();
if (
!(otherModelObj instanceof MAVOElement) || // skip non-MAVO element
!(mavoModelObj.eClass().getName().equals(otherModelObj.eClass().getName())) || // skip different type
mavoModelObj.getFormulaVariable().equals(((MAVOElement) otherModelObj).getFormulaVariable()) // skip current element
) {
continue;
}
EObject otherModelObjContainer = otherModelObj.eContainer();
boolean isMergeable = (mavoModelObj.isVar() || ((MAVOElement) otherModelObj).isVar()) && ( // ok one is V
(modelObjContainer == otherModelObjContainer) || ( // ok same container (also recursion closure when containers are root)
modelObjContainer instanceof MAVOElement && // ok different container: MAVO element
modelObjContainer.eClass().getName().equals(otherModelObjContainer.eClass().getName()) && // ok different container: same type
getMergeableFormulaVars(mavoModel, (MAVOElement) modelObjContainer).contains(((MAVOElement) otherModelObjContainer).getFormulaVariable()) // ok different container: mergeable
)
);
if (whichFormulaVars != isMergeable) {
continue;
}
formulaVars.add(((MAVOElement) otherModelObj).getFormulaVariable());
}
return formulaVars;
}
public static @NonNull Set<String> getMergeableFormulaVars(@NonNull MAVORoot mavoModel, @NonNull MAVOElement mavoModelObj) {
return getVFormulaVars(mavoModel, mavoModelObj, true);
}
public static @NonNull Set<String> getUnmergeableFormulaVars(@NonNull MAVORoot mavoModel, @NonNull MAVOElement mavoModelObj) {
return getVFormulaVars(mavoModel, mavoModelObj, false);
}
private static @NonNull Map<String, MAVOElement> getMAVOModelObjects(@NonNull MAVORoot mavoModel, @NonNull Predicate<? super EObject> filterLambda) {
Iterable<EObject> iterable = () -> mavoModel.eAllContents();
Map<String, MAVOElement> mavoModelObjs = StreamSupport.stream(iterable.spliterator(), false)
.filter(filterLambda)
.map(modelObj -> (MAVOElement) modelObj)
.collect(Collectors.toMap(
MAVOElement::getFormulaVariable,
mavoModelObj -> mavoModelObj));
return mavoModelObjs;
}
public static @NonNull Map<String, MAVOElement> getAllMAVOModelObjects(@NonNull MAVORoot mavoModel) {
Predicate<? super EObject> filterLambda = modelObj -> modelObj instanceof MAVOElement;
return getMAVOModelObjects(mavoModel, filterLambda);
}
public static @NonNull Map<String, MAVOElement> getAllMAVOModelObjects(@NonNull Model model) throws MMINTException {
EObject rootModelObj = model.getEMFInstanceRoot();
if (!(rootModelObj instanceof MAVORoot)) {
throw new MMINTException("Not a MAVO model");
}
return getAllMAVOModelObjects((MAVORoot) rootModelObj);
}
public static @NonNull Map<String, MAVOElement> getAnnotatedMAVOModelObjects(@NonNull MAVORoot mavoModel) {
Predicate<? super EObject> filterLambda = modelObj ->
modelObj instanceof MAVOElement && (
((MAVOElement) modelObj).isMay() ||
((MAVOElement) modelObj).isSet() ||
((MAVOElement) modelObj).isVar()
);
return getMAVOModelObjects(mavoModel, filterLambda);
}
public static @NonNull Map<String, MAVOElement> getAnnotatedMAVOModelObjects(@NonNull Model model) throws MMINTException {
EObject rootModelObj = model.getEMFInstanceRoot();
if (!(rootModelObj instanceof MAVORoot)) {
throw new MMINTException("Not a MAVO model");
}
return getAnnotatedMAVOModelObjects((MAVORoot) rootModelObj);
}
}