blob: 6858742637eebc69daadee7dac4385f6951687ff [file] [log] [blame]
package org.eclipse.emf.henshin.multicda.cda;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import org.eclipse.emf.henshin.interpreter.Engine;
import org.eclipse.emf.henshin.interpreter.Match;
import org.eclipse.emf.henshin.interpreter.RuleApplication;
import org.eclipse.emf.henshin.interpreter.impl.EngineImpl;
import org.eclipse.emf.henshin.interpreter.impl.RuleApplicationImpl;
import org.eclipse.emf.henshin.interpreter.util.HenshinEGraph;
import org.eclipse.emf.henshin.model.Action;
import org.eclipse.emf.henshin.model.Action.Type;
import org.eclipse.emf.henshin.model.Attribute;
import org.eclipse.emf.henshin.model.Edge;
import org.eclipse.emf.henshin.model.Graph;
import org.eclipse.emf.henshin.model.GraphElement;
import org.eclipse.emf.henshin.model.HenshinFactory;
import org.eclipse.emf.henshin.model.Mapping;
import org.eclipse.emf.henshin.model.MappingList;
import org.eclipse.emf.henshin.model.NestedCondition;
import org.eclipse.emf.henshin.model.Node;
import org.eclipse.emf.henshin.model.Parameter;
import org.eclipse.emf.henshin.model.ParameterMapping;
import org.eclipse.emf.henshin.model.Rule;
import org.eclipse.emf.henshin.multicda.cda.conflict.ConflictReason;
import org.eclipse.emf.henshin.multicda.cda.dependency.DependencyReason;
import org.eclipse.emf.henshin.multicda.cda.units.Reason;
import org.eclipse.emf.henshin.multicda.cda.units.Span;
import org.eclipse.emf.henshin.multicda.cda.units.SymmetricReason;
import org.eclipse.emf.henshin.multicda.cpa.result.Conflict;
import org.eclipse.emf.henshin.multicda.cpa.result.CriticalElement;
import org.eclipse.emf.henshin.multicda.cpa.result.CriticalPair;
import org.eclipse.emf.henshin.multicda.cpa.result.Dependency;
import org.eclipse.emf.henshin.preprocessing.RulePair;
public abstract class Utils {
private static final String INVERTED_TAG = "_Inv";
private static HenshinFactory factory = HenshinFactory.eINSTANCE;
public static Rule invertRule(Rule rule1) {
Copier ruleC = new Copier();
Rule invRule = (Rule) ruleC.copy(rule1);
ruleC.copyReferences();
String d = rule1.getDescription();
invRule.setDescription((d == null ? "" : d) + INVERTED_TAG);
Graph newLhs = invRule.getRhs();
Graph newRhs = invRule.getLhs();
newLhs.setName("LHS");
invRule.setLhs(newLhs);
newRhs.setName("RHS");
invRule.setRhs(newRhs);
MappingList mappings = invRule.getMappings();
for (Mapping mapping : mappings) {
Node original = mapping.getOrigin();
Node image = mapping.getImage();
mapping.setImage(original);
mapping.setOrigin(image);
}
return invRule;
}
public static Rule invertRuleForForbid(Rule rule1) {
Rule invRule = invertRule(rule1);
for (Node n : invRule.getRhs().getNodes())
if (invRule.getMappings().getOrigin(n) == null) {
Node lhsNode = HenshinFactory.eINSTANCE.createNode(invRule.getLhs(), n.getType(), n.getName());
invRule.getMappings().add(HenshinFactory.eINSTANCE.createMapping(lhsNode, n));
for (Attribute a : n.getAttributes())
HenshinFactory.eINSTANCE.createAttribute(lhsNode, a.getType(), a.getValue());
}
for (Edge e : invRule.getRhs().getEdges()) {
Node lhsSource = invRule.getMappings().getOrigin(e.getSource());
Node lhsTarget = invRule.getMappings().getOrigin(e.getTarget());
if (lhsSource.getOutgoing(e.getType(), lhsTarget) == null)
HenshinFactory.eINSTANCE.createEdge(lhsSource, lhsTarget, e.getType());
}
return invRule;
}
public static List<RulePair> prepareNonDeletingVersions(List<Rule> rules) {
List<RulePair> copiesOfRulesWithoutDeletion = new LinkedList<RulePair>();
for (Rule delete : rules) {
Copier copier = new Copier();
Rule nonDelete = (Rule) copier.copy(delete);
String d = nonDelete.getDescription();
nonDelete.setDescription((d == null ? "" : d) + "_NonDelete");
copier.copyReferences();
for (Node n : nonDelete.getActionNodes(new Action(Action.Type.DELETE))) {
Node image = HenshinFactory.eINSTANCE.createNode(nonDelete.getRhs(), n.getType(), n.getName());
nonDelete.getMappings().add(HenshinFactory.eINSTANCE.createMapping(n, image));
}
Map<Node, Set<Pair<Attribute, Attribute>>> nodes = getAttributeChanges(nonDelete);
for (Node node : nodes.keySet()) {
Set<Pair<Attribute, Attribute>> attributes = nodes.get(node);
for (Pair<Attribute, Attribute> attribute : attributes)
if (attribute.second == null)
HenshinFactory.eINSTANCE.createAttribute(nonDelete.getMappings().getImage(node, null),
attribute.first.getType(), attribute.first.getValue());
}
for (Edge e : nonDelete.getActionEdges(new Action(Action.Type.DELETE))) {
Node s = nonDelete.getMappings().getImage(e.getSource(), null);
Node t = nonDelete.getMappings().getImage(e.getTarget(), null);
nonDelete.getRhs().getEdges().add(HenshinFactory.eINSTANCE.createEdge(s, t, e.getType()));
}
copiesOfRulesWithoutDeletion.add(new RulePair(nonDelete, delete));
}
return copiesOfRulesWithoutDeletion;
}
public static List<Rule> prepareNoneDeletingsVersionsRules(List<Rule> rules) {
List<Rule> result = new ArrayList<Rule>();
List<RulePair> pairs = prepareNonDeletingVersions(rules);
for (RulePair rulePair : pairs) {
result.add(rulePair.getCopy());
}
return result;
}
public static Rule nonDeleteRule(Rule rule) {
List<Rule> result = new ArrayList<Rule>();
result.add(rule);
List<RulePair> pairs = prepareNonDeletingVersions(result);
return pairs.get(0).getCopy();
}
public static Set<Rule> createNACRules(Rule rule1) {
return getNestedRules(rule1, true);
}
public static Set<Rule> createPACRules(Rule rule1) {
return getNestedRules(rule1, false);
}
private final static String NAC_TAG = "NAC";
private final static String PAC_TAG = "PAC";
public static Set<Rule> getNestedRules(Rule rule, boolean isNac) {
int id = 0;
int nodeId = 0;
Set<Rule> result = new HashSet<>();
for (NestedCondition nac : isNac ? rule.getLhs().getNACs() : rule.getLhs().getPACs()) {
Rule ncRule = factory.createRule(rule.getName());
String d = ncRule.getDescription();
String nested = PAC_TAG;
if (isNac)
nested = NAC_TAG;
ncRule.setDescription((d == null ? "" : d) + "_" + nested + "rule_" + id++);
Copier cL = new Copier();
Graph newLhs = (Graph) cL.copy(rule.getLhs());
cL.copyReferences();
if (isNac)
newLhs = factory.createGraph();
newLhs.setDescription(": this is the " + nested + " of the Original Rule");
Copier cR = new Copier();
Graph newRhs = (Graph) cR.copy(rule.getRhs());
cR.copyReferences();
if (isNac)
newRhs = factory.createGraph();
newRhs.setDescription(": this is the " + nested + " of the Original Rule");
ncRule.setLhs(newLhs);
ncRule.setRhs(newRhs);
Map<Parameter, Parameter> parameterMap = new HashMap<>();
for (Parameter p : rule.getParameters()) {
parameterMap.put(p, factory.createParameter(p.getName()));
ncRule.getParameters().add(parameterMap.get(p));
}
for (ParameterMapping pm : rule.getParameterMappings()) {
ParameterMapping pM = factory.createParameterMapping();
pM.setSource(parameterMap.get(pm.getSource()));
pM.setTarget(parameterMap.get(pm.getTarget()));
ncRule.getParameterMappings().add(pM);
}
Map<Node, Node> map = new HashMap<>();
if (isNac) {
for (Node n : rule.getLhs().getNodes()) {
Node newLhsNode = factory.createNode(newLhs, n.getType(), n.getName());
Node newRhsNode = factory.createNode(newRhs, n.getType(), n.getName());
map.put(n, newLhsNode);
Mapping createdMapping = factory.createMapping(newLhsNode, newRhsNode);
ncRule.getMappings().add(createdMapping);
ncRule.getMappings().add(factory.createMapping(n, newLhsNode));
}
} else
for (Node n : rule.getLhs().getNodes()) {
Node newL = (Node) cL.get(n);
Node nR = rule.getMappings().getImage(n, null);
ncRule.getMappings().add(factory.createMapping(n, newL));
map.put(n, newL);
if (nR != null) {
Node newR = (Node) cR.get(nR);
ncRule.getMappings().add(factory.createMapping(newL, newR));
}
}
for (Edge e : rule.getLhs().getEdges()) {
Node source = map.get(e.getSource());
Node target = map.get(e.getTarget());
if (source != null && target != null && source.getOutgoing(e.getType(), target) == null) {
factory.createEdge(source, target, e.getType());
factory.createEdge(ncRule.getMappings().getImage(source, null),
ncRule.getMappings().getImage(target, null), e.getType());
}
}
for (Node fn : nac.getConclusion().getNodes()) {
Node fOrigin = nac.getMappings().getOrigin(fn);
Node FNL = null;
Node FNR = null;
if (fOrigin != null) {
FNL = map.get(fOrigin);
FNR = ncRule.getMappings().getImage(FNL, null);
} else {
char type = isNac ? 'f' : 'r';
String name = fn.getName();
if (name == null) {
name = "|" + type + nodeId + "|";
nodeId++;
}
FNL = factory.createNode(newLhs, fn.getType(), name);
FNR = factory.createNode(newRhs, fn.getType(), name);
Mapping createdMapping = factory.createMapping(FNL, FNR);
ncRule.getMappings().add(createdMapping);
}
map.put(fn, FNL);
if (!isNac)
for (Attribute a : fn.getAttributes()) {
if (FNL.getAttribute(a.getType()) == null) {
factory.createAttribute(FNL, a.getType(), a.getValue());
factory.createAttribute(FNR, a.getType(), a.getValue());
}
}
}
for (Edge fe : nac.getConclusion().getEdges()) {
Node source = map.get(fe.getSource());
Node target = map.get(fe.getTarget());
if (source != null && target != null && source.getOutgoing(fe.getType(), target) == null) {
factory.createEdge(source, target, fe.getType());
if (ncRule.getMappings().getImage(source, null) != null
&& ncRule.getMappings().getImage(target, null) != null)
factory.createEdge(ncRule.getMappings().getImage(source, null),
ncRule.getMappings().getImage(target, null), fe.getType());
}
}
result.add(ncRule);
}
return result;
}
public static Node addNodeToGraph(Node nodeInRule1, Node nodeInRule2, Graph S1, Set<Mapping> rule1Mappings,
Set<Mapping> rule2Mappings) {
EClass subNodeType = identifySubNodeType(nodeInRule1, nodeInRule2);
Node commonNode = factory.createNode(S1, subNodeType,
nodeInRule1.getName() + Reason.NODE_SEPARATOR + nodeInRule2.getName());
rule1Mappings.add(factory.createMapping(commonNode, nodeInRule1));
rule2Mappings.add(factory.createMapping(commonNode, nodeInRule2));
return commonNode;
}
public static boolean nodeTypeEqual(Node node1, Node node2) {
return identifySubNodeType(node1, node2) != null;
}
/**
* identify the type of the both nodes which is the subtype of the other node.
*
* @param node1
* @param node2
* @return returns the subnode type if one of both is, otherwise null.
*/
public static EClass identifySubNodeType(Node node1, Node node2) {
if (node1 == null || node2 == null)
return null;
if (node1.getType() == node2.getType() || node1.getType().getEAllSuperTypes().contains(node2.getType()))
return node1.getType();
if (node2.getType().getEAllSuperTypes().contains(node1.getType()))
return node2.getType();
return null;
}
public static void checkNull(Object o) throws IllegalArgumentException {
checkNull(o, "object");
}
public static void checkNull(Object o, String name) throws IllegalArgumentException {
if (null == o)
throw new IllegalArgumentException(name + " must not be null");
}
public boolean isRuleSupported(Rule rule) {
if (rule.getMultiRules().size() > 0) {
if (rule.getLhs().getPACs().size() > 0)
throw new RuntimeException("positive application conditions (PAC) are not supported");
}
return true;
}
public static void removeRedundantNodes(Graph graph2Copy, Collection<Mapping> mappingsS2Rule1Copies,
Collection<Mapping> mappingsS2Rule2Copies, List<Node> toDeleteInG2Copy) {
List<Mapping> toDeleteMappingsToRule1 = new LinkedList<Mapping>();
for (Mapping mapS2ToRule1 : mappingsS2Rule1Copies) {
if (toDeleteInG2Copy.contains(mapS2ToRule1.getOrigin())) {
toDeleteMappingsToRule1.add(mapS2ToRule1);
}
}
mappingsS2Rule1Copies.removeAll(toDeleteMappingsToRule1);
List<Mapping> mappingsInRule2ToRemove = new LinkedList<Mapping>();
for (Mapping mappingOfSpan2InRule2 : mappingsS2Rule2Copies) {
if (toDeleteInG2Copy.contains(mappingOfSpan2InRule2.getOrigin())) {
mappingsInRule2ToRemove.add(mappingOfSpan2InRule2);
}
}
mappingsS2Rule2Copies.removeAll(mappingsInRule2ToRemove);
graph2Copy.getNodes().removeAll(toDeleteInG2Copy);
}
public static Map<Node, Node> getS2toS1Map(Reason span1, Reason span2) {
Map<Node, Node> s2ToS1 = new HashMap<Node, Node>();
for (Node n1 : span1.getGraph().getNodes()) {
for (Node n2 : span2.getGraph().getNodes()) {
if (identifySubNodeType(n1, n2) != null) {
boolean sameImageInRule1 = (span1.getMappingIntoRule1(n1).getImage() == span2
.getMappingIntoRule1(n2).getImage());
boolean sameImageInRule2 = (span1.getMappingIntoRule2(n1).getImage() == span2
.getMappingIntoRule2(n2).getImage());
if (sameImageInRule1 && sameImageInRule2) {
s2ToS1.put(n2, n1);
} else if (sameImageInRule1 ^ sameImageInRule2) {
return null;
}
}
}
}
return s2ToS1;
}
public static Map<CriticalPair, Reason> compare(Set<CriticalPair> cps, Set<Reason> reasons) {
Map<CriticalPair, Reason> result = new HashMap<>();
if (reasons == null || cps == null)
return result;
for (CriticalPair cp : cps)
for (Reason reason : reasons) {
boolean foundElement = false;
if (reason instanceof SymmetricReason)
reason = ((SymmetricReason) reason).getS1();
if ((cp instanceof Conflict && reason instanceof ConflictReason)
|| (cp instanceof Dependency && reason instanceof DependencyReason)) {
List<CriticalElement> delCE = cp.getCriticalElements();
Set<GraphElement> delRE = reason.getDeletionElementsInRule1_2();
if (delCE.size() == delRE.size())
for (GraphElement d1 : delRE) {
foundElement = false;
for (CriticalElement d2 : delCE) {
if ((d1 instanceof Node && d2.elementInFirstRule instanceof Node)
|| (d1 instanceof Node && d2.elementInFirstRule instanceof Attribute)
|| (d1 instanceof Edge && d2.elementInFirstRule instanceof Edge)) {
if (d1.toString().equals(d2.toString())) {
foundElement = true;
break;
}
}
}
}
if (foundElement) {
result.put(cp, reason);
break;
}
}
}
return result;
}
public static Set<DanglingEdge> findDanglingEdgesOfRule1(Rule rule, List<Mapping> embedding) {
HashMap<Node, Node> mapL1toG = new HashMap<Node, Node>();
HashMap<Node, Node> mapGtoL1 = new HashMap<Node, Node>();
for (Mapping mapping : embedding) {
mapL1toG.put(mapping.getOrigin(), mapping.getImage());
mapGtoL1.put(mapping.getImage(), mapping.getOrigin());
}
Set<DanglingEdge> danglingEdges = new HashSet<DanglingEdge>();
EList<Node> l1DeletingNodes = rule.getActionNodes(new Action(Action.Type.DELETE));
for (Node l1Deleting : l1DeletingNodes) {
Node poDeleting = mapL1toG.get(l1Deleting);
// Since the pushout can have parallel edges with the same type, source,
// and target, we compare the number of parallel edges.
for (Edge edgePO : poDeleting.getOutgoing()) {
Node l1DelTarget = mapGtoL1.get(edgePO.getTarget());
int parallelPO = getParallelEdges(poDeleting, edgePO.getTarget(), edgePO.getType()).size();
int parallelLhs1 = getParallelEdges(l1Deleting, l1DelTarget, edgePO.getType()).size();
if (l1DelTarget == null)
danglingEdges.add(new DanglingEdge(edgePO, DanglingCase.targetDangling));
else if (parallelLhs1 < parallelPO)
danglingEdges.add(new DanglingEdge(edgePO, DanglingCase.unspecifiedEdge));
}
for (Edge edgePO : poDeleting.getIncoming()) {
Node l1DelSource = mapGtoL1.get(edgePO.getSource());
int parallelPO = getParallelEdges(edgePO.getSource(), poDeleting, edgePO.getType()).size();
int parallelLhs1 = getParallelEdges(l1DelSource, l1Deleting, edgePO.getType()).size();
if (l1DelSource == null)
danglingEdges.add(new DanglingEdge(edgePO, DanglingCase.sourceDangling));
else if (parallelLhs1 < parallelPO)
danglingEdges.add(new DanglingEdge(edgePO, DanglingCase.unspecifiedEdge));
}
}
return danglingEdges;
}
public static Set<Edge> getParallelEdges(Node source, Node target, EReference type) {
Set<Edge> result = new HashSet<Edge>();
if (source == null || target == null)
return result;
for (Edge edge : source.getOutgoing()) {
if (edge.getTarget() == target && edge.getType() == type)
result.add(edge);
}
return result;
}
/**
* @param graph
* @return
*/
public static EPackage graphToEPackage(Graph g) {
Set<String> added = new HashSet<String>();
EPackage result = EcoreFactory.eINSTANCE.createEPackage();
result.setName(g.getName());
result.setNsURI("http://cdapackage/" + g.getName());
result.setNsPrefix("CDAPackage");
EList<EClassifier> classifiers = result.getEClassifiers();
for (Node node : g.getNodes()) {
EClass n = getSimpleClassifier(node);
added.add(n.getName());
classifiers.add(n);
}
for (Edge edge : g.getEdges()) {
EClass s = getSimpleClassifier(edge.getSource());
EClass t = getSimpleClassifier(edge.getTarget());
if (!added.contains(s.getName())) {
classifiers.add(s);
added.add(s.getName());
} else
s = (EClass) result.getEClassifier(s.getName());
if (!added.contains(t.getName())) {
classifiers.add(t);
added.add(t.getName());
} else
t = (EClass) result.getEClassifier(t.getName());
EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setName(edge.getType().getName());
ref.setEType(t);
s.getEStructuralFeatures().add(ref);
}
return result;
}
public static EPackage spanToEPackage(Span r) {
Set<String> added = new HashSet<String>();
EPackage result = EcoreFactory.eINSTANCE.createEPackage();
result.setName(r.getRule1().getName() + Reason.NODE_SEPARATOR + r.getRule2().getName());
result.setNsURI("http://cdapackage/" + r.getRule1().getName() + "/" + r.getRule2().getName() + "/"
+ r.getClass().getSimpleName());
result.setNsPrefix("CDAPackage");
EList<EClassifier> classifiers = result.getEClassifiers();
Set<GraphElement> deletions = r.getDeletionElementsInRule1_2();
for (Node node : r.getGraph().getNodes()) {
EClass n = getClassifier(r, deletions, node);
added.add(n.getName());
classifiers.add(n);
}
for (Edge edge : r.getGraph().getEdges()) {
EClass s = getClassifier(r, deletions, edge.getSource());
EClass t = getClassifier(r, deletions, edge.getTarget());
if (!added.contains(s.getName())) {
classifiers.add(s);
added.add(s.getName());
} else
s = (EClass) result.getEClassifier(s.getName());
if (!added.contains(t.getName())) {
classifiers.add(t);
added.add(t.getName());
} else
t = (EClass) result.getEClassifier(t.getName());
EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setName(edge.getType().getName());
if (!r.getRule1().getRhs().getEdges().contains(edge)) {
ref.setName("#" + ref.getName() + "#");
}
ref.setEType(t);
s.getEStructuralFeatures().add(ref);
}
return result;
}
public static EClass getSimpleClassifier(Node node) {
EClassifier nodeClass = node.getType();
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName(node.getName() + ":" + nodeClass.getName());
for (Attribute a : node.getAttributes()) {
Copier cAttribute = new Copier();
EAttribute at = (EAttribute) cAttribute.copy(a.getType());
cAttribute.copyReferences();
at.setName(a.getType().getName() + "=" + a.getValue());
eclass.getEStructuralFeatures().add(at);
}
return eclass;
}
public static EClass getClassifier(Span r, Set<GraphElement> deletions, Node node) {
EClassifier nodeClass = node.getType();
EClass eclass = EcoreFactory.eINSTANCE.createEClass();
eclass.setName(node.getName() + ":" + nodeClass.getName());
Node image1L = r.getMappingIntoRule1(node).getImage();
Node image2L = r.getMappingIntoRule2(node).getImage();
Node image1R = r.getRule1().getMappings().getImage(image1L, null);
Node image2R = r.getRule2().getMappings().getImage(image2L, null);
for (Attribute a1L : image1L.getAttributes()) {
String name1 = "";
if (image1R != null) {
Attribute a1R = image1R.getAttribute(a1L.getType());
if (a1R != null && a1L.getValue().equals(a1R.getValue()))
name1 = a1L.getValue();
else
name1 = a1L.getValue() + "->" + (a1R == null ? " " : a1R.getValue());
} else
name1 = a1L.getValue();
Attribute a2L = image2L.getAttribute(a1L.getType());
String name2 = " ";
if (image2R != null) {
Attribute a2R = image2R.getAttribute(a1L.getType());
if (a2R != null && a1L.getValue().equals(a2R.getValue()))
name2 = a1L.getValue();
else
name2 = (a2L == null ? " " : a2L.getValue()) + "->" + (a2R == null ? " " : a2R.getValue());
} else if (a2L != null)
name2 = a2L.getValue();
Copier cAttribute = new Copier();
EAttribute at = (EAttribute) cAttribute.copy(a1L.getType());
cAttribute.copyReferences();
at.setName(a1L.getType().getName() + "=" + name1 + " " + Reason.NODE_SEPARATOR + " " + name2);
eclass.getEStructuralFeatures().add(at);
}
if (image1R != null)
for (Attribute a1R : image1R.getAttributes())
if (image1L.getAttribute(a1R.getType()) == null) {
String name1 = " ->" + a1R.getValue();
Attribute a2L = image2L.getAttribute(a1R.getType());
Attribute a2R = image2R.getAttribute(a1R.getType());
String name2 = (a2L == null ? " " : a2L.getValue()) + "->" + (a2R == null ? " " : a2R.getValue());
Copier cAttribute = new Copier();
EAttribute at = (EAttribute) cAttribute.copy(a1R.getType());
cAttribute.copyReferences();
at.setName(a1R.getType().getName() + "=" + name1 + " " + Reason.NODE_SEPARATOR + " " + name2);
eclass.getEStructuralFeatures().add(at);
}
if (deletions.contains(node))
eclass.setName("#" + eclass.getName() + "#");
return eclass;
}
public static boolean isNcRule(Rule rule, boolean... nac) {
String d = rule.getDescription();
Boolean n = nac.length == 0 ? null : nac[0];
if (d != null)
if (n == null && (d.contains(Utils.NAC_TAG) || d.contains(Utils.PAC_TAG)))
return true;
else if (n != null && ((n && d.contains(Utils.NAC_TAG)) || (!n && d.contains(Utils.PAC_TAG))))
return true;
return false;
}
public static boolean isRealNcNode(Node n) {
if (n == null)
return false;
Rule r = n.getGraph().getRule();
if (isNcRule(r)) {
if (n.getGraph().isRhs())
n = r.getMappings().getOrigin(n);
Node origin = r.getMappings().getOrigin(n);
if (origin == null)
return true;
for (Attribute a : n.getAttributes())
if (origin.getAttribute(a.getType()) == null)
return true;
}
return false;
}
public static boolean isRealNcNode(Node n, boolean nac) {
if (!isRealNcNode(n))
return false;
Rule r = n.getGraph().getRule();
return r.getDescription() != null
&& ((nac && r.getDescription().contains(NAC_TAG)) || (!nac && r.getDescription().contains(PAC_TAG)));
}
public static boolean isInverted(Rule rule) {
String dsc = rule.getDescription();
dsc = dsc == null ? "" : dsc;
int parts = (dsc.length() - dsc.replaceAll(INVERTED_TAG, "").length()) / INVERTED_TAG.length();
return parts % 2 == 1;
}
public static boolean attributesCheck(Span reason) {
for (Mapping m : reason.getMappingsInRule1()) {
Node n1L = m.getImage();
Node n2L = reason.getMappingIntoRule2(m.getOrigin()).getImage();
if (isInverted(reason.getRule1())) {
if (isNcRule(reason.getRule2(), true)) {
if (!strongAttributesCheck(n2L, n1L))
return false;
} else if (!attributesCheck(n2L, n1L))
return false;
} else if (!attributesCheck(n1L, n2L))
return false;
}
return true;
}
public static boolean attributesCheck(Node node1, Node node2) {
if (identifySubNodeType(node1, node2) == null)
return false;
for (Attribute attr1L : node1.getAttributes()) {
Attribute attr2L = node2.getAttribute(attr1L.getType());
if (attr2L != null && !Utils.equalAttributes(attr1L, attr2L))
return false;
}
return true;
}
public static boolean strongAttributesCheck(Node node1, Node node2) {
if (identifySubNodeType(node1, node2) == null)
return false;
for (Attribute attr1L : node1.getAttributes()) {
Attribute attr2L = node2.getAttribute(attr1L.getType());
if (!Utils.equalAttributes(attr1L, attr2L))
return false;
}
return true;
}
public static boolean equalAttributes(Attribute a1, Attribute a2) {
if (a1 == null || a2 == null || a1.getType() != a2.getType())
return false;
Rule r1 = a1.getNode().getGraph().getRule();
Rule r2 = a2.getNode().getGraph().getRule();
for (Parameter p : r1.getParameters())
if (p.getName().equals(a1.getValue()))
return true;
for (Parameter p : r2.getParameters())
if (p.getName().equals(a2.getValue()))
return true;
return a1.getValue().equals(a2.getValue());
}
public static Map<Node, Set<Pair<Attribute, Attribute>>> getAttributeChanges(Rule rule1) {
Map<Node, Set<Pair<Attribute, Attribute>>> changeUse = new HashMap<>();
for (Node nL : rule1.getLhs().getNodes()) {
Pair<Node, Set<Pair<Attribute, Attribute>>> attributes = getAttributeChanges(nL);
if (attributes != null)
if (!attributes.second.isEmpty())
changeUse.put(attributes.first, attributes.second);
}
return changeUse;
}
public static Pair<Node, Set<Pair<Attribute, Attribute>>> getAttributeChanges(Node node) {
if (node.getGraph().isRhs()) {
return null;
}
Pair<Node, Set<Pair<Attribute, Attribute>>> attributes = new Pair<>(node, new HashSet<>());
Set<Attribute> added = new HashSet<>();
for (Attribute a : node.getActionAttributes(new Action(Action.Type.CREATE))) {
attributes.second.add(new Pair<>(null, a));
added.add(a);
}
for (Attribute a : node.getActionAttributes(new Action(Action.Type.DELETE))) {
attributes.second.add(new Pair<>(a, null));
added.add(a);
}
for (Attribute a1 : node.getAttributes())
if (!added.contains(a1)) {
Attribute a2 = node.getGraph().getRule().getMappings().getImage(node, null).getAttribute(a1.getType());
if (a2 != null && !a1.getValue().equals(a2.getValue()))
attributes.second.add(new Pair<>(a1, a2));
}
return attributes;
}
public static boolean haveCommonDeletionElement(Reason current, ConflictReason extensionCandidate) {
Set<GraphElement> deletionElementsCur = current.getDeletionElementsInRule1();
Set<GraphElement> deletionElementsCand = extensionCandidate.getDeletionElementsInRule1();
return !Collections.disjoint(deletionElementsCur, deletionElementsCand);
}
public static Set<ConflictReason> computeMinimalConflictReasons(Reason current, Set<ConflictReason> remaining) {
Set<ConflictReason> result = new HashSet<>();
for (ConflictReason mcr : remaining) {
if (mcr.isMinimalReason() && !Utils.haveCommonDeletionElement(current, mcr)) {
ConflictReason initialReason = ReasonFactory.eINSTANCE.createJoinedReason(current, mcr);
if (initialReason != null) {
result.add(initialReason);
result.addAll(computeMinimalConflictReasons(initialReason, remaining));
}
}
}
return result;
}
private static Engine engine = new EngineImpl();
public static boolean checkNcReason(Span reason, Rule originalR1, Rule originalR2) {
if (!containsNCElements(reason))
return false;
if (validateCreateForbidReason(reason, originalR1, originalR2))
return true;
extendPreservedPartsOfReason(reason);
return validateCreateForbidReason(reason, originalR1, originalR2);
}
public static boolean validateCreateForbidReason(Span reason, Rule originalR1, Rule originalR2) {
// 4. Create PO: (R1 -> H1 <- N2)
Pushout pH = new Pushout(reason.getRule1(), reason, reason.getRule2());
Graph H = pH.getResultGraph();
if (checkSuperTypes(H))
return false;
// 5. execute r1i on R1 -> H1, if possible, otherwise break:
Pushout pG = new Pushout(reason.getRule1(), reason, reason.getRule2());
Graph G = pG.getResultGraph();
HenshinEGraph g;
try {
g = new HenshinEGraph(G);
} catch (Exception e) {
return false;
}
RuleApplication app = new RuleApplicationImpl(engine);
app.setEGraph(g);
app.setUnit(reason.getRule1());
Match match = getMatch(pG.getRule1Mappings(), g, reason.getRule1());
app.setCompleteMatch(match);
if (!app.execute(null))
return false;
// if (G.getNodes().isEmpty())
// return true;
// Der Comatch is L1 -> G. There is a Trace H1 -o-> G.
Match comatch = app.getResultMatch();
Set<Mapping> trace = getTrace(H, G);
// 6. Check, if L1 -> G AC1 accepts. Otherwise break.
Copier c = new Copier();
Graph GCopy = (Graph) c.copy(G);
c.copyReferences();
HenshinEGraph gCopy = new HenshinEGraph(GCopy);
app.setEGraph(gCopy);
app.setUnit(originalR1);
app.setPartialMatch(comatch);
if (!app.execute(null))
return false;
// 7. Set L2 -> H1 = L2 -> N2 -> H1.
List<Mapping> L2N2 = getNacMappingsOfNacRule(reason.getRule2());
List<Mapping> N2H1 = pH.getRule2Mappings();
List<Mapping> L2H1 = composeMappings(L2N2, N2H1);
// 8. Set L2 -o-> G = L2 -> H1 -o-> G. Check, if L2 -o-> G is total. Otherwise break.
List<Mapping> H1G = new ArrayList<>(trace);
List<Mapping> L2G = composeMappings(L2H1, H1G);
if (L2G.size() != L2N2.size())
return false;
try {
g = new HenshinEGraph(G);
} catch (Exception e) {
return false;
}
app.setEGraph(g);
app.setUnit(originalR2);
match = getMatch(L2G, g, originalR2);
app.setCompleteMatch(match);
if (!app.execute(null))
return false;
return true;
}
public static boolean attributesDetected(Span reason) {
for (Node n : reason.getRule1().getLhs().getNodes())
if (!n.getAttributes().isEmpty())
return true;
for (Node n : reason.getRule2().getLhs().getNodes())
if (!n.getAttributes().isEmpty())
return true;
return false;
}
public static void deleteParameters(Graph g, Rule r1, Rule r2) {
Set<Attribute> toRemove = new HashSet<>();
if (!r1.getParameters().isEmpty())
for (Node n : g.getNodes()) {
for (Attribute a : n.getAttributes())
if (r1.getParameter(a.getValue()) != null)
toRemove.add(a);
n.getAttributes().removeAll(toRemove);
toRemove.clear();
}
if (!r2.getParameters().isEmpty())
for (Node n : g.getNodes()) {
for (Attribute a : n.getAttributes())
if (r2.getParameter(a.getValue()) != null)
toRemove.add(a);
n.getAttributes().removeAll(toRemove);
toRemove.clear();
}
}
private static boolean checkSuperTypes(Graph graph) {
for (Edge e : graph.getEdges()) {
EClass typeA = (EClass) e.getType().getEType();
EClass typeB = e.getTarget().getType();
if (isSuper(typeA, typeB))
return true;
typeB = e.getSource().getType();
if (isSuper(typeA, typeB))
return true;
}
return false;
}
public static boolean isSuper(EClass subClass, EClass superClass) {
if (subClass.getESuperTypes().contains(superClass))
return true;
for (EClass eclass : subClass.getESuperTypes())
if (isSuper(eclass, superClass))
return true;
return false;
}
public static boolean containsNCElements(Span reason) {
for (Mapping map : reason.getMappingsInRule2()) {
Node image = map.getImage();
if (isRealNcNode(image))
return true;
}
for (Edge e : reason.getGraph().getEdges()) {
Node source = reason.getMappingIntoRule2(e.getSource()).getImage();
Node target = reason.getMappingIntoRule2(e.getTarget()).getImage();
source = reason.getRule2().getMappings().getOrigin(source);
target = reason.getRule2().getMappings().getOrigin(target);
if (source.getOutgoing(e.getType(), target) == null)
return true;
}
return false;
}
public static void extendPreservedPartsOfReason(Span reason) {
Set<Node> p1nodes = new HashSet<>();
Set<Node> p2nodes = new HashSet<>();
for (Node node : reason.getRule1().getActionNodes(new Action(Action.Type.PRESERVE))) {
if (reason.getMappingFromGraphToRule1(node) == null)
p1nodes.add(node);
}
for (Node node : reason.getRule2().getLhs().getNodes()) {
if (reason.getMappingFromGraphToRule2(node) == null
&& reason.getRule2().getMappings().getImage(node, null) != null)
p2nodes.add(node);
}
Map<Node, Node> maps = mapNodes(p1nodes, p2nodes, null);
for (Node n : maps.keySet()) {
Node n2 = maps.get(n);
String name = n.getName() + "_" + n2.getName();
if (reason.getGraph().getNode(name) == null) {
Node reasonNode = HenshinFactory.eINSTANCE.createNode(reason.getGraph(), n.getType(), name);
reason.getMappingsInRule1().add(HenshinFactory.eINSTANCE.createMapping(reasonNode, n));
reason.getMappingsInRule2().add(HenshinFactory.eINSTANCE.createMapping(reasonNode, n2));
for (Edge e : n.getOutgoing())
if (e.getAction().getType() == Type.PRESERVE) {
Mapping target = reason.getMappingFromGraphToRule1(e.getTarget());
if (target != null && reasonNode.getOutgoing(e.getType(), target.getOrigin()) == null)
HenshinFactory.eINSTANCE.createEdge(reasonNode, target.getOrigin(), e.getType());
}
for (Edge e : n.getIncoming())
if (e.getAction().getType() == Type.PRESERVE) {
Mapping source = reason.getMappingFromGraphToRule1(e.getSource());
if (source != null && source.getOrigin().getOutgoing(e.getType(), reasonNode) == null)
HenshinFactory.eINSTANCE.createEdge(source.getOrigin(), reasonNode, e.getType());
}
for (Edge e : n2.getOutgoing())
if (e.getAction().getType() == Type.PRESERVE) {
Mapping target = reason.getMappingFromGraphToRule1(e.getTarget());
if (target != null && reasonNode.getOutgoing(e.getType(), target.getOrigin()) == null)
HenshinFactory.eINSTANCE.createEdge(reasonNode, target.getOrigin(), e.getType());
}
for (Edge e : n2.getIncoming())
if (e.getAction().getType() == Type.PRESERVE) {
Mapping source = reason.getMappingFromGraphToRule1(e.getSource());
if (source != null && source.getOrigin().getOutgoing(e.getType(), reasonNode) == null)
HenshinFactory.eINSTANCE.createEdge(source.getOrigin(), reasonNode, e.getType());
}
}
}
}
private static Match getMatch(List<Mapping> neededMappings, HenshinEGraph g, Rule rule) {
for (Match m : engine.findMatches(rule, g, null)) {
if (m.getNodeTargets().size() == neededMappings.size()) {
boolean found = true;
for (Mapping mapping : neededMappings) {
Node node = mapping.getOrigin();
EObject graphNode = m.getNodeTarget(node);
node = mapping.getImage();
if (g.getObject2NodeMap().get(graphNode) != node) {
found = false;
break;
}
}
if (found)
return m;
}
}
return null;
}
private static List<Mapping> getNacMappingsOfNacRule(Rule r) {
List<Mapping> result = new ArrayList<>();
for (Mapping m : r.getMappings())
if (!r.getLhs().getNodes().contains(m.getOrigin()))
result.add(factory.createMapping(m.getOrigin(), m.getImage()));
return result;
}
public static List<Mapping> composeMappings(List<Mapping> map1, List<Mapping> map2) {
List<Mapping> result = new ArrayList<>();
for (Mapping m1 : map1)
for (Mapping m2 : map2)
if (m1.getImage() == m2.getOrigin()) {
result.add(HenshinFactory.eINSTANCE.createMapping(m1.getOrigin(), m2.getImage()));
break;
}
return result;
}
public static Set<Mapping> getTrace(Graph G, Graph H) {
Set<Mapping> result = new HashSet<>();
Map<Node, Node> map = new HashMap<>();
for (Node nH : H.getNodes())
for (Node nG : G.getNodes()) {
if (nH.getName() != null && nG.getName() != null && map.get(nG) == null
&& nH.getName().equals(nG.getName())) {
map.put(nG, nH);
result.add(HenshinFactory.eINSTANCE.createMapping(nG, nH));
break;
}
}
return result;
}
private static Map<EClass, Set<Node>> classifyNodes(Set<Node> nodes) {
Map<EClass, Set<Node>> result = new HashMap<>();
for (Node n : nodes) {
Set<Node> classNodes = result.get(n.getType());
if (classNodes == null) {
classNodes = new HashSet<>();
result.put(n.getType(), classNodes);
}
classNodes.add(n);
}
return result;
}
public static Map<Node, Node> mapNodes(Set<Node> nodes1, Set<Node> nodes2, Map<Node, Node> result,
boolean... delete) {
return mapNodes(nodes1, nodes2, nodes2, result, delete.length != 0 && delete[0]);
}
public static Map<Node, Node> mapNodes(Node nodes1, Node nodes2, Map<Node, Node> result, boolean... delete) {
Set<Node> n1 = new HashSet<>();
Set<Node> n2 = new HashSet<>();
n1.add(nodes1);
n2.add(nodes2);
return mapNodes(n1, n2, result, delete);
}
public static Map<Node, Node> mapNodes(Node nodes1, Set<Node> nodes2, Map<Node, Node> result, boolean... delete) {
Set<Node> n1 = new HashSet<>();
n1.add(nodes1);
return mapNodes(n1, nodes2, result, delete);
}
public static Map<Node, Node> mapNodes(Set<Node> nodes1, Node nodes2, Map<Node, Node> result, boolean... delete) {
Set<Node> n2 = new HashSet<>();
n2.add(nodes2);
return mapNodes(nodes1, n2, result, delete);
}
public static Map<Node, Node> mapNodes(Set<Node> nodesOriginal1, Set<Node> nodesOriginal2, Set<Node> nodes2,
Map<Node, Node> result, boolean allActionTypes) {
//Tries to compute a mapping from nodesOriginal1 to nodesOriginal2
//When there is a mapping, result is not empty
if (result == null)
result = new HashMap<>();
for (Node n2 : nodes2) {
for (Node n1 : nodesOriginal1)
if (result.get(n1) == null) {
if (Utils.strongAttributesCheck(n2, n1)) {
boolean found = true;
for (Edge e2 : n2.getOutgoing())
if (found && nodesOriginal2.contains(e2.getTarget())) {
EList<Edge> e1 = n1.getOutgoing(e2.getType());
boolean foundEdge = false;
for (Edge e : e1)
if (allActionTypes || e.getAction().getType() == Action.Type.PRESERVE) {
//&& nodesOriginal1.contains(e.getTarget())
if (result.get(e.getTarget()) == null || result.get(e.getTarget())== e2.getTarget()) {
foundEdge = true;
break;
}
}
if (e1.size() != 0) {
found = foundEdge;
}
}
if (found)
for (Edge e2 : n2.getIncoming())
if (found && nodesOriginal2.contains(e2.getSource())) {
EList<Edge> e1 = n1.getIncoming(e2.getType());
boolean foundEdge = false;
for (Edge e : e1)
if (allActionTypes || e.getAction().getType() == Action.Type.PRESERVE) {
//&& nodesOriginal1.contains(e.getTarget())
// in the follwoing: getTarget() should be getSource()
if (result.get(e.getSource()) == null || result.get(e.getSource())== e2.getSource()) {
foundEdge = true;
break;
}
}
if (e1.size() != 0) {
found = foundEdge;
}
}
if (found) {
result.put(n1, n2);
Set<Node> remained = new HashSet<>(nodes2);
remained.remove(n2);
if (remained.isEmpty()) {
return result;
}
mapNodes(nodesOriginal1, nodesOriginal2, remained, result, allActionTypes);
//was nodesOriginal2
if (result.size() == Math.min(nodesOriginal1.size(),nodesOriginal2.size())) {
//if (result.size() == nodesOriginal2.size() - remained.size()) {
return result;
}
result.remove(n1);
}
}
}
}
return result;
}
public static <T extends Span> Set<T> computeCreateEdgeDeleteNode(Set<T> s2Set) {
Set<T> result = new HashSet<>();
for (T s2 : s2Set)
for (Edge cEdge : s2.getRule2().getActionEdges(new Action(Action.Type.CREATE))) {
Node originS = s2.getRule2().getMappings().getOrigin(cEdge.getSource());
boolean sourceIsDel = false;
boolean targetIsDel = false;
if (originS != null && s2.getMappingFromGraphToRule2(originS) != null) {
originS = s2.getMappingFromGraphToRule2(originS).getOrigin();
if (originS != null && s2.getMappingIntoRule1(originS) != null) {
originS = s2.getMappingIntoRule1(originS).getImage();
sourceIsDel = originS.getAction().getType() == Action.Type.DELETE;
}
}
Node originT = s2.getRule2().getMappings().getOrigin(cEdge.getTarget());
if (originT != null && s2.getMappingFromGraphToRule2(originT) != null) {
originT = s2.getMappingFromGraphToRule2(originT).getOrigin();
if (originT != null && s2.getMappingIntoRule1(originT) != null) {
originT = s2.getMappingIntoRule1(originT).getImage();
targetIsDel = originT.getAction().getType() == Action.Type.DELETE;
}
}
if (sourceIsDel && targetIsDel) {
Edge e1 = originS.getOutgoing(cEdge.getType(), originT);
if (e1 == null)
result.add(ReasonFactory.eINSTANCE.createCEDNReason(s2));
} else if ((sourceIsDel ^ targetIsDel))
result.add(ReasonFactory.eINSTANCE.createCEDNReason(s2));
}
return result;
}
public static <T extends Span> Set<T> filterDoubles(Set<T> spans) {
Set<T> toRemove = new HashSet<>();
for (T s : spans) {
if (!s.isForbid() && !s.isRequire()) {
for (T s2 : spans)
if (s != s2 && s.equalElements(s2)) {
toRemove.add(s);
break;
}
}
}
spans.removeAll(toRemove);
return spans;
}
public static enum DanglingCase {
sourceDangling, targetDangling, unspecifiedEdge
}
public static class DanglingEdge {
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((danglingCase == null) ? 0 : danglingCase.hashCode());
result = prime * result + ((edge == null) ? 0 : edge.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DanglingEdge other = (DanglingEdge) obj;
if (danglingCase != other.danglingCase)
return false;
if (edge == null) {
if (other.edge != null)
return false;
} else if (!edge.equals(other.edge))
return false;
return true;
}
@Override
public String toString() {
return "DanglingEdge [edge=" + edge + ", danglingCase=" + danglingCase + "]";
}
public Edge edge;
public DanglingCase danglingCase;
public DanglingEdge(Edge edge, DanglingCase danglingCase) {
super();
this.edge = edge;
this.danglingCase = danglingCase;
}
public Edge getEdge() {
return edge;
}
public void setEdge(Edge edge) {
this.edge = edge;
}
public DanglingCase getDanglingCase() {
return danglingCase;
}
public void setDanglingCase(DanglingCase danglingCase) {
this.danglingCase = danglingCase;
}
}
}