/******************************************************************************* * Copyright (c) 2010-2015 Henshin developers. 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: * TU Berlin, University of Luxembourg, SES S.A. *******************************************************************************/ package de.tub.tfs.henshin.editor.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.Assert; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.henshin.model.BinaryFormula; import org.eclipse.emf.henshin.model.Formula; import org.eclipse.emf.henshin.model.Graph; import org.eclipse.emf.henshin.model.HenshinPackage; import org.eclipse.emf.henshin.model.Mapping; import org.eclipse.emf.henshin.model.Module; import org.eclipse.emf.henshin.model.NamedElement; import org.eclipse.emf.henshin.model.NestedCondition; import org.eclipse.emf.henshin.model.Node; import org.eclipse.emf.henshin.model.Rule; import org.eclipse.emf.henshin.model.UnaryFormula; import org.eclipse.gef.EditPart; import de.tub.tfs.henshin.editor.HenshinTreeEditor; import de.tub.tfs.henshin.model.layout.LayoutSystem; import de.tub.tfs.muvitor.ui.IDUtil; /** * The Class ModelUtil. */ public class ModelUtil { /** * Gets the epackage references. * * @param model * the model * @param parent * the parent * @return the e package references */ public static String getEPackageReferences(EPackage model, Module parent) { String errorMsg = ""; Set<EObject> referencedGraphs = new HashSet<EObject>(); Set<EObject> referencedRules = new HashSet<EObject>(); for (EClassifier clazz : model.getEClassifiers()) { referencedGraphs.addAll(getEObjectsWithReference(parent, clazz, HenshinPackage.GRAPH)); referencedRules.addAll(getEObjectsWithReference(parent, clazz, HenshinPackage.RULE)); } for (EObject eObject : referencedGraphs) { if (!errorMsg.isEmpty()) { errorMsg += "\n"; } errorMsg += "\tGraph [" + ((Graph) eObject).getName() + "]"; } for (EObject eObject : referencedRules) { if (!errorMsg.isEmpty()) { errorMsg += "\n"; } errorMsg += "\tRule [" + ((Rule) eObject).getName() + "]"; } return errorMsg.isEmpty() ? null : errorMsg; } /** * Gets the eobjects with reference. * * @param transSys * the trans sys * @param clazz * the clazz * @param featureID * the feature id * @return the e objects with reference */ private static Set<EObject> getEObjectsWithReference( Module transSys, EClassifier clazz, int featureID) { Set<EObject> referencedEObjects = new HashSet<EObject>(); switch (featureID) { case HenshinPackage.GRAPH: for (Graph graph : transSys.getInstances()) { if (isReferenced(graph, clazz, transSys)) { referencedEObjects.add(graph); } } break; case HenshinPackage.RULE: EList<Rule> rules = HenshinUtil.getRules(transSys); for (Rule rule : rules) { if (isReferenced(rule.getLhs(), clazz, transSys)) { referencedEObjects.add(rule); } if (isReferenced(rule.getRhs(), clazz, transSys)) { referencedEObjects.add(rule); } } break; default: break; } return referencedEObjects; } /** * Checks if is referenced. * * @param graph * the graph * @param clazz * the clazz * @param parent * the parent * @return true, if is referenced */ private static boolean isReferenced(Graph graph, EClassifier clazz, Module parent) { for (Node node : graph.getNodes()) { String type = node.getType().getName(); if (clazz.getName().equals(type)) { return true; } } return false; } /** * Gets the new child distinct name. * * @param <Child_T> * the generic type * @param obj * the obj * @param childFeatureID * the child feature id * @param nameBase * the name base * @return the new child distinct name */ public static <Child_T extends NamedElement> String getNewChildDistinctName( EObject obj, int childFeatureID, String nameBase) { return getNewChildDistinctName(obj, childFeatureID, nameBase, ""); } @SuppressWarnings("unchecked") public static <Child_T extends NamedElement> String getNewChildDistinctName( EObject obj, int childFeatureID, String nameBase, String nameAddition) { HashSet<String> forbiddenNames = new HashSet<String>(); final EStructuralFeature eStructuralFeature = obj.eClass() .getEStructuralFeature(childFeatureID); for (Child_T instance : (Collection<Child_T>) obj .eGet(eStructuralFeature)) { forbiddenNames.add(instance.getName()); } // generates a new distinct name int id = 0; String newName; do { newName = nameBase + id++ + nameAddition; } while (forbiddenNames.contains(newName)); return newName; } public static List<Mapping> getMappings(final Formula formula) { if (formula != null) { if (formula instanceof NestedCondition) { return ((NestedCondition) formula).getMappings(); } else if (formula instanceof UnaryFormula) { return getMappings(((UnaryFormula) formula).getChild()); } else { final List<Mapping> result = new ArrayList<Mapping>(); result.addAll(getMappings(((BinaryFormula) formula).getLeft())); result.addAll(getMappings(((BinaryFormula) formula).getRight())); return result; } } return Collections.emptyList(); } /** * Gets the distinct nc name. * * @param graph * the graph * @return the distinct nc name */ public static String getDistinctNCName(final Graph graph) { if (graph != null) { final Graph lhs = getLhs(graph); final Formula formula = lhs.getFormula(); final Set<String> forbiddenNames = getExistNames(formula, null); // Generates a distinct name final String nameBase = "AC"; int i = 0; String distinctName; do { distinctName = nameBase + i++; } while (forbiddenNames.contains(distinctName)); return distinctName; } throw new IllegalArgumentException("The given graph must not be null!"); } /** * Gets the exist names. * * @param formula * the formula * @param existNames * the exist names * @return the exist names */ static Set<String> getExistNames(Formula formula, Set<String> existNames) { if (existNames == null) { existNames = new HashSet<String>(); } if (formula instanceof NestedCondition) { NestedCondition ac = (NestedCondition) formula; Graph conclusion = ac.getConclusion(); if (conclusion != null) { existNames.add(conclusion.getName()); existNames.addAll(getExistNames(conclusion.getFormula(), null)); } } else if (formula instanceof UnaryFormula) { getExistNames(((UnaryFormula) formula).getChild(), existNames); } else if (formula instanceof BinaryFormula) { getExistNames(((BinaryFormula) formula).getLeft(), existNames); getExistNames(((BinaryFormula) formula).getRight(), existNames); } return existNames; } /** * Checks, if the given {@code graph} is a LHS. * * @param graph * The graph to check. * @return {@code true} if the given {@code graph} is a LHS, {@code false} * otherwise. * * @deprecated use {@link Graph#isLhs()} instead. */ public static boolean isLhs(final Graph graph) { if (graph != null) { final Rule rule = getRule(graph); if (rule != null) { return graph.equals(rule.getLhs()); } } return false; } /** * Gets a rule which contains the given {@code graph} and returns the LHS. * * @param graph * A graph whose LHS is found. * @return A LHS of the given {@code graph}. */ private static Graph getLhs(Graph graph) { if (graph != null) { EObject parent = graph.eContainer(); while (parent != null && !(parent instanceof Rule)) { parent = parent.eContainer(); } if (parent != null && parent instanceof Rule) { return ((Rule) parent).getLhs(); } } return null; } /** * Gets the all nacs. * * @param rule * the rule * @return the all nacs */ public static List<NestedCondition> getAllNacs(Rule rule) { List<NestedCondition> result = new ArrayList<NestedCondition>(); Graph lhs = rule.getLhs(); Formula formula = lhs.getFormula(); getAllNacs(result, formula); return result; } /** * Gets the all nacs. * * @param nacs * the nacs * @param formula * the formula * @return the all nacs */ private static void getAllNacs(List<NestedCondition> nacs, Formula formula) { if (nacs == null) { nacs = new ArrayList<NestedCondition>(); } if (formula instanceof NestedCondition) { nacs.add((NestedCondition) formula); } else if (formula instanceof BinaryFormula) { BinaryFormula binaryFormula = (BinaryFormula) formula; getAllNacs(nacs, binaryFormula.getLeft()); getAllNacs(nacs, binaryFormula.getRight()); } } /** * Gets the rule. * * @param object * the object * @return the rule */ public static Rule getRule(EObject object) { Rule rule = null; EObject f = object; while (!(f instanceof Rule) && f != null) { f = f.eContainer(); } if (f != null) { rule = (Rule) f; } return rule; } /** * @param rule * Rule to check. * @param isLhs * This value is only evaluated if the given rule is used as * multi rule in amalgamation unit. Otherwise, this value is not * relevant. * @return The mapping list. */ public static List<Mapping> getMappings(final Rule rule, final boolean isLhs) { return rule.getMappings(); } /** * Gets the root {@link Module} for a given model object. * * @param eObject * the e object * @return the root {@link Module} * * @deprecated Use {@link HenshinUtil#getTransformationSystem(EObject)} * instead. */ public static Module getTransformationSystem(EObject model) { HenshinTreeEditor editor = (HenshinTreeEditor) IDUtil .getHostEditor(model); if (editor != null) { return editor.getModelRoot(Module.class); } return null; } /** * @param editpart * @param toFindType * @return */ @SuppressWarnings("unchecked") public static <T> T find(EditPart editpart, Class<T> toFindType) { Assert.isLegal(toFindType != null); if (editpart == null) { return null; } Object model = editpart.getModel(); if (toFindType.isInstance(model)) { return (T) model; } return find(editpart.getParent(), toFindType); } /** * @param model * @param type * @return */ @SuppressWarnings("unchecked") public static <T extends EObject> T findAncestor(EObject model, Class<T> type) { Assert.isLegal(type != null); if (model == null) { return null; } if (type.isInstance(model)) { return (T) model; } return findAncestor(model.eContainer(), type); } /** * Convenient method to get the root {@link LayoutSystem}. * * @param eobject * the eobject * @return the layout system */ public static LayoutSystem getLayoutSystem(EObject eobject) { HenshinTreeEditor editor = (HenshinTreeEditor) IDUtil .getHostEditor(eobject); if (editor != null) { return editor.getModelRoot(LayoutSystem.class); } return null; } /** * Convenient method to get the properly typed model root for a given model * object being hosted in an {@link HenshinTreeEditor}. * * @param model * a model object * @param toFind * the type of the returned model root * * @return the correctly typed model root or <code>null</code>, if the given * <code>model</code> is not hosted in an editor. */ public static <T extends EObject> T getModelRoot(EObject model, Class<T> toFind) { EObject search = model; while (search != null) { HenshinTreeEditor hostingEditor = (HenshinTreeEditor) IDUtil .getHostEditor(search); if (hostingEditor != null) { return hostingEditor.getModelRoot(toFind); } search = search.eContainer(); } return null; } /** * Searches in a given root model object's tree for all {@link EObject}s * with a {@link EStructuralFeature} pointing to a given model object. * * @param model * @param rootModel * @param refFeature * * @return */ public static List<EObject> getReferences(EObject model, EObject rootModel, EStructuralFeature refFeature) { List<EObject> result = new LinkedList<EObject>(); if (rootModel != null && refFeature != null) { TreeIterator<EObject> iter = rootModel.eAllContents(); while (iter.hasNext()) { EObject toFind = iter.next(); if (toFind.eClass().getEAllStructuralFeatures() .contains(refFeature)) { Object refObj = toFind.eGet(refFeature); if (refFeature.isMany()) { if (((List<?>) refObj).contains(model)) { result.add(toFind); } } else if (model != toFind && model == refObj) { result.add(toFind); } } } } return result; } /** * @param model * @param refType * @param rootModel * @param refFeature * @return */ @SuppressWarnings("unchecked") public static <T> List<T> getReferences(EObject model, Class<T> refType, EObject rootModel, EStructuralFeature refFeature) { List<T> result = new LinkedList<T>(); if (rootModel != null && refFeature != null) { TreeIterator<EObject> iter = rootModel.eAllContents(); while (iter.hasNext()) { EObject toFind = iter.next(); if (refType.isInstance(toFind)) { Object refObj = toFind.eGet(refFeature); if (refFeature.isMany()) { if (((List<?>) refObj).contains(model)) { result.add((T) toFind); } } else if (model != toFind && model == refObj) { result.add((T) toFind); } } } } return result; } public static Collection<EPackage> getEPackagesOfGraph(Graph graph) { if (graph != null) { Set<EPackage> ePackages = new HashSet<EPackage>(); EList<Node> nodes = graph.getNodes(); for (Node node : nodes) { ePackages.add(node.getType().getEPackage()); } return ePackages; } return null; } }