/******************************************************************************* * 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.tgg.interpreter.util; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.henshin.interpreter.EGraph; import org.eclipse.emf.henshin.interpreter.matching.constraints.DomainSlot; import org.eclipse.emf.henshin.model.Attribute; import org.eclipse.emf.henshin.model.Edge; import org.eclipse.emf.henshin.model.Formula; import org.eclipse.emf.henshin.model.Graph; import org.eclipse.emf.henshin.model.Mapping; import org.eclipse.emf.henshin.model.Module; import org.eclipse.emf.henshin.model.NestedCondition; import org.eclipse.emf.henshin.model.Node; import de.tub.tfs.henshin.tgg.ImportedPackage; import de.tub.tfs.henshin.tgg.TGG; import de.tub.tfs.henshin.tgg.TNode; import de.tub.tfs.henshin.tgg.TripleComponent; import de.tub.tfs.henshin.tgg.TripleGraph; import de.tub.tfs.henshin.tgg.interpreter.impl.NodeTypes; import de.tub.tfs.henshin.tgg.interpreter.impl.TggHenshinEGraph; /** * The Class Nodeutil Holds many helpful static functions for operating on * nodes. */ public class NodeUtil { private static final String EXCEPTION_NODE_IS_NOT_TNODE = "Triple component of node cannot be determined, because it is not of type TNode (node in a triple graph)."; /** * get the mapping in rule of given node of rhs * * @param rhsNode * @return */ public static Mapping getNodeMapping(Node rhsNode) { EList<Mapping> mappingList = rhsNode.getGraph().getRule().getMappings(); for (Mapping m : mappingList) { if (m.getImage() == rhsNode) { return m; } } return null; } /** * checks if given node has a nac mapping * * @param node * @return */ public static Boolean hasNodeNacMapping(Node node) { if (node == null || node.getGraph() == null) return false; Formula formula = node.getGraph().getFormula(); if (formula != null) { TreeIterator<EObject> iter = node.getGraph().getFormula() .eAllContents(); while (iter.hasNext()) { EObject o = iter.next(); if (o instanceof NestedCondition) { NestedCondition nc = (NestedCondition) o; for (Mapping m : nc.getMappings()) { if (m.getOrigin() == node) { return true; } } } } } return false; } /** * get nac mapping of given node * * @param nc * the nested condition with all mappings * @param node * @return (returns null if there's no mapping) */ public static Mapping getNodeNacMapping(NestedCondition nc, Node node) { EList<Mapping> list = nc.getMappings(); for (Mapping m : list) { if (m.getImage() == node) { return m; } } return null; } /** * searches all mappings belongs to given node * * @param rhsNode * @return a set of Mappings belongs to the given rhsNode (empty list if * there are no mapping) */ public static List<Mapping> getNodeNacMappings(Node rhsNode) { List<Mapping> nacMappings = new ArrayList<Mapping>(); Mapping ruleMapping = RuleUtil.getRHSNodeMapping(rhsNode); if (ruleMapping != null) { Node lhsNode = ruleMapping.getOrigin(); Formula formula = lhsNode.getGraph().getFormula(); if (formula != null) { TreeIterator<EObject> iter = ruleMapping.getOrigin().getGraph() .getFormula().eAllContents(); while (iter.hasNext()) { EObject o = iter.next(); if (o instanceof NestedCondition) { NestedCondition nc = (NestedCondition) o; for (Mapping m : nc.getMappings()) { if (m.getOrigin() == lhsNode) { nacMappings.add(m); } } } } } } return nacMappings; } public static void deleteNodeNacMapping(Node node) { } /** * find all nodeLayouts to specific EPackage * * @param p * EPackage for source, target oder correspondence * @param g * Graph containing the nodes * @return set of nodes belonging to EPackage p */ public static Set<Node> getNodes(EPackage p, Graph g) { Set<Node> set = new HashSet<Node>(); if (p != null) { for (Node n : g.getNodes()) { if (p.eContents().contains(n.getType())) { set.add(n); } } } return set; } /** * find all nodeLayouts to specified list of EPackages * * @param p * EPackage for source, target oder correspondence * @param g * Graph containing the nodes * @return set of nodes belonging to EPackage p */ public static Set<Node> getNodes(List<EPackage> pkgs, Graph g) { Set<Node> nodes = new HashSet<Node>(); for (EPackage p : pkgs) { nodes.addAll(getNodes(p, g)); } return nodes; } /** * checks whether a specific EClass is a source type in given layoutSystem * * @param tgg * the layoutSystem * @param type * the EClass for check * @return true if specific EClass is a source type */ public static boolean isSourceClass(TGG tgg, EClass c) { return TripleComponent.SOURCE == TggUtil.getEObjectTripleComponent(tgg, c); } /** * Checks if a node is a soruce node. * * @param node * @return true if it is a source node, else false */ public static boolean isSourceNode(TNode node) { return (TripleComponent.SOURCE == node.getComponent()); } /** * Checks if a node is a correspondence node. * * @param node * @return true if it is a correspondence node, else false */ public static boolean isCorrespondenceNode(TNode node) { return (TripleComponent.CORRESPONDENCE == node.getComponent()); } /** * Checks if a node is a target node. * * @param node * @return true if it is a target node, else false */ public static boolean isTargetNode(TNode node) { return (TripleComponent.TARGET == node.getComponent()); } /** * checks whether a specific EClass is a target type in given layoutSystem * * @param tgg * the layoutSystem * @param type * the EClass for check * @return true if specific EClass is a target type */ public static boolean isTargetClass(TGG tgg, EClass c) { return TripleComponent.TARGET == TggUtil.getEObjectTripleComponent(tgg, c); } /** * checks whether a specific EClass is a correspondence type in given * layoutSystem * * @param tgg * the layoutSystem * @param type * the EClass for check * @return true if specific EClass is a correspondence type */ public static boolean isCorrespondenceClass(TGG tgg, EClass c) { return TripleComponent.CORRESPONDENCE == TggUtil .getEObjectTripleComponent(tgg, c); } /** * computes the triple component of a given graph node * * @param node * the graph node to by analysed * @return the triple component of the graph node */ public static TripleComponent getComponentFromPosition(TNode node) { if (node == null) return TripleComponent.SOURCE; TripleGraph tripleGraph = (TripleGraph) node.getGraph(); // position is left of SC divider if (node.getX() <= tripleGraph.getDividerSC_X()) return TripleComponent.SOURCE; // position is right of SC divider and left of CT divider else if (node.getX() <= tripleGraph.getDividerCT_X()) return TripleComponent.CORRESPONDENCE; // position is (right of SC divider and) right of CT divider return TripleComponent.TARGET; } /** * determines whether at least one package is loaded for each triple * component * * @param importedPkgs * @return */ public static boolean isTypeGraphComplete( EList<ImportedPackage> importedPkgs) { boolean isSetSourceTG = false; boolean isSetCorrespondenceTG = false; boolean isSetTargetTG = false; ImportedPackage pkg; Iterator<ImportedPackage> iter = importedPkgs.iterator(); while (iter.hasNext()) { pkg = iter.next(); switch (pkg.getComponent()) { case SOURCE: isSetSourceTG = true; case CORRESPONDENCE: isSetCorrespondenceTG = true; case TARGET: isSetTargetTG = true; } } return (isSetSourceTG && isSetCorrespondenceTG && isSetTargetTG); } // returns whether the node is translated already in the LHS public static Boolean getNodeIsTranslated(Node node) { if (((TNode) node).getMarkerType() != null) { if (RuleUtil.Not_Translated_Graph.equals(((TNode) node) .getMarkerType())) // node is translated by the rule - it is not yet translated return false; else if (RuleUtil.Translated_Graph.equals(((TNode) node) .getMarkerType())) // node is context element - it is already translated return true; } // node is not marked with a relevant marker return null; } // returns true, if the node is marked with the "NEW" marker public static boolean isNew(Node rn) { return (((TNode) rn).getMarkerType() != null && ((TNode) rn) .getMarkerType().equals(RuleUtil.NEW)); } public static TripleComponent guessTripleComponent(TNode node) { TGG tgg = null; Module m = TggUtil.getModuleFromElement(node); if (m instanceof TGG) tgg = (TGG) m; TripleComponent comp = guessTripleComponentRaw(node, 4, new HashSet<TNode>(), tgg); if (comp == null) comp = getComponentFromPosition(node); node.eSetDeliver(false); if (tgg == null) return comp; List<ImportedPackage> pkgs = NodeTypes.getImportedPackagesOfComponent( tgg.getImportedPkgs(), comp); if (node.getType() != null && NodeTypes.contains(node.getType().getEPackage(), pkgs)) { node.setComponent(comp); } else { pkgs = NodeTypes.getImportedPackagesOfComponent( tgg.getImportedPkgs(), TripleComponent.SOURCE); List<ImportedPackage> pkgt = NodeTypes .getImportedPackagesOfComponent(tgg.getImportedPkgs(), TripleComponent.TARGET); List<ImportedPackage> pkgc = NodeTypes .getImportedPackagesOfComponent(tgg.getImportedPkgs(), TripleComponent.CORRESPONDENCE); if (node.getType() != null && node.getType().getEPackage() != null) { if (!NodeTypes.contains(node.getType().getEPackage(), pkgs)) { if (!NodeTypes.contains(node.getType().getEPackage(), pkgt)) { if (NodeTypes.contains(node.getType().getEPackage(), pkgc)) comp = TripleComponent.CORRESPONDENCE; } else { comp = TripleComponent.TARGET; } } else { comp = TripleComponent.SOURCE; } } node.setComponent(comp); } node.eSetDeliver(true); return comp; } public static TripleComponent guessTripleComponentRaw(TNode node, TGG tgg) { return guessTripleComponentRaw(node, 4, new HashSet<TNode>(), tgg); } public static TripleComponent guessTripleComponentRaw(TNode node, int checkDeep, HashSet<TNode> sources, TGG tgg) { sources.add(node); if (tgg == null) return null; List<ImportedPackage> pkgs = NodeTypes.getImportedPackagesOfComponent( tgg.getImportedPkgs(), TripleComponent.SOURCE); List<ImportedPackage> pkgt = NodeTypes.getImportedPackagesOfComponent( tgg.getImportedPkgs(), TripleComponent.TARGET); List<ImportedPackage> pkgc = NodeTypes.getImportedPackagesOfComponent( tgg.getImportedPkgs(), TripleComponent.CORRESPONDENCE); if (node.getComponent() != null) { return node.getComponent(); } if (node.getType() != null && node.getType().getEPackage() != null) { if (!NodeTypes.contains(node.getType().getEPackage(), pkgs)) { if (!NodeTypes.contains(node.getType().getEPackage(), pkgt)) { if (NodeTypes.contains(node.getType().getEPackage(), pkgc)) return TripleComponent.CORRESPONDENCE; } else { return TripleComponent.TARGET; } } else { if (!NodeTypes.contains(node.getType().getEPackage(), pkgt) && !NodeTypes.contains(node.getType().getEPackage(), pkgc)) return TripleComponent.SOURCE; } } if (checkDeep == 0) return null; TripleComponent c = null; List<Edge> outgoing = new LinkedList<Edge>(); outgoing.addAll(node.getOutgoing()); List<Edge> incoming = new LinkedList<Edge>(); incoming.addAll(node.getIncoming()); for (Edge edge : incoming) { if (sources.contains(edge.getSource())) continue; if (c != null) { if (TripleComponent.CORRESPONDENCE == c) c = guessTripleComponentRaw((TNode) edge.getSource(), checkDeep - 1, (HashSet<TNode>) sources.clone(), tgg); else { TripleComponent c2 = guessTripleComponentRaw( (TNode) edge.getSource(), checkDeep - 1, (HashSet<TNode>) sources.clone(), tgg); if (c != c2 && TripleComponent.CORRESPONDENCE != c2) return TripleComponent.CORRESPONDENCE; } } else { c = guessTripleComponentRaw((TNode) edge.getSource(), checkDeep - 1, (HashSet<TNode>) sources.clone(), tgg); } } if (c != null && c != TripleComponent.CORRESPONDENCE) return c; for (Edge edge : outgoing) { if (sources.contains(edge.getTarget())) continue; if (c != null) { if (c == TripleComponent.CORRESPONDENCE) c = guessTripleComponentRaw((TNode) edge.getTarget(), checkDeep - 1, (HashSet<TNode>) sources.clone(), tgg); else if (c != guessTripleComponentRaw((TNode) edge.getTarget(), checkDeep - 1, (HashSet<TNode>) sources.clone(), tgg)) if (guessTripleComponentRaw((TNode) edge.getTarget(), checkDeep - 1, (HashSet<TNode>) sources.clone(), tgg) != null) return TripleComponent.CORRESPONDENCE; } else { c = guessTripleComponentRaw((TNode) edge.getTarget(), checkDeep - 1, (HashSet<TNode>) sources.clone(), tgg); } } if (TripleComponent.CORRESPONDENCE == c) return null; else return c; } /** * Find the attribute with a specific type. Is just working when there is * not more than one one type of attribute in a node. * * @param graphNode * source node * @param type * type of the attribute * @return the corresponding attribute of graphNode */ public static Attribute findAttribute(Node graphNode, EAttribute type) { for (Attribute a : graphNode.getAttributes()) { if (a.getType() == type) { return a; } } return null; } public static Node getGraphNode(DomainSlot slot, EGraph graph) { return ((TggHenshinEGraph) graph).getObject2NodeMap().get( slot.getValue()); } public static Node getGraphNode(EObject slot, EGraph graph) { return ((TggHenshinEGraph) graph).getObject2NodeMap().get(slot); } /** * checks whether a node belongs to the source component * * @param node * the graph node to be analysed * @return true, if the node belongs to the source component */ public static boolean isSourceNodeByPosition(TNode node) { if (node == null) return false; // position has to be left of SC divider TripleGraph tripleGraph = (TripleGraph) node.getGraph(); return node.getX() <= tripleGraph.getDividerSC_X(); } }