/*******************************************************************************
* 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.tggeditor.commands.create.rule;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.henshin.model.Attribute;
import org.eclipse.emf.henshin.model.AttributeCondition;
import org.eclipse.emf.henshin.model.Edge;
import org.eclipse.emf.henshin.model.HenshinFactory;
import org.eclipse.emf.henshin.model.IndependentUnit;
import org.eclipse.emf.henshin.model.Module;
import org.eclipse.emf.henshin.model.Node;
import org.eclipse.emf.henshin.model.Parameter;
import org.eclipse.emf.henshin.model.Rule;
import org.eclipse.emf.henshin.model.Unit;
import de.tub.tfs.henshin.tgg.TAttribute;
import de.tub.tfs.henshin.tgg.TEdge;
import de.tub.tfs.henshin.tgg.TGGRule;
import de.tub.tfs.henshin.tgg.TNode;
import de.tub.tfs.henshin.tggeditor.util.AttributeUtil;
import de.tub.tfs.henshin.tgg.interpreter.util.RuleUtil;
import de.tub.tfs.henshin.tggeditor.util.AttributeUtil;
public abstract class GenerateOpRuleCommand extends ProcessRuleCommand {
private static final String RULE_FOLDER = "RuleFolder";
protected String OP_RULE_CONTAINER_PREFIX = "OPRule_";
protected String OP_RULE_FOLDER = "OPRuleFolder";
protected String OP_RULES_PNG = "OPRules.png";
public GenerateOpRuleCommand(Rule rule) {
this(rule,null);
}
protected abstract boolean filterNode(TNode node);
protected class OpRuleNodeProcessor implements NodeProcessor{
private static final String REF_PREFIX = "ref";
@Override
public void process(Node oldNodeRHS, Node newNode) {
Node ruleTNode = newNode;
// case: node is marked to be created by the TGG rule, thus it shall be translated by the FT rule
if (RuleUtil.NEW.equals(((TNode)oldNodeRHS).getMarkerType())){
Node tNodeLHS = copyNodePure(oldNodeRHS, newNode.getGraph().getRule().getLhs());
setNodeLayoutAndMarker(ruleTNode, oldNodeRHS,
RuleUtil.Translated);
// set marker [!tr] in LHS, for checking the matching constraint during execution
setNodeMarker(tNodeLHS, RuleUtil.Not_Translated_Graph);
setMapping(tNodeLHS, ruleTNode);
// update all markers for the attributes
TAttribute newAttLHS = null;
TAttribute newAttRHS = null;
for (Attribute oldAttribute : oldNodeRHS.getAttributes()) {
newAttRHS = (TAttribute) getCopiedObject(oldAttribute);
if (RuleUtil.NEW.equals(newAttRHS.getMarkerType())){
newAttLHS = (TAttribute) copyAtt(oldAttribute, tNodeLHS);
AttributeUtil.setAttributeMarker(newAttRHS, RuleUtil.Translated);
// marker needed for matching constraint
AttributeUtil.setAttributeMarker(newAttLHS, RuleUtil.Not_Translated_Graph);
setValueOfMarkedAttribute(newNode, newAttLHS,
newAttRHS, oldAttribute);
}
}
oldRhsNodes2TRhsNodes.put(oldNodeRHS, ruleTNode);
oldLhsNodes2TLhsNodes.put(RuleUtil.getLHSNode(oldNodeRHS),
tNodeLHS);
} else {
// case: node is not created, i.e., in LHS or in NAC
// set marker that it has to be translated already
TAttribute tAttributeRHS = null;
TAttribute tAttributeLHS = null;
TNode tNodeLHS = (TNode) RuleUtil.getLHSNode(ruleTNode);
// case: node is in NAC
if (tNodeLHS == null) {
if (RuleUtil.TR_UNSPECIFIED.equals(((TNode)oldNodeRHS).getMarkerType())){
setNodeMarker(ruleTNode, RuleUtil.TR_UNSPECIFIED);
}
else{
setNodeMarker(ruleTNode, RuleUtil.Translated_Graph);
}
for (Attribute attr : oldNodeRHS.getAttributes()) {
tAttributeRHS = (TAttribute) getCopiedObject(attr);
tAttributeLHS = (TAttribute) RuleUtil.getLHSAttribute(tAttributeRHS);
// case: attribute in NAC has marker "unspecified"
if (RuleUtil.TR_UNSPECIFIED.equals(tAttributeRHS
.getMarkerType())){
AttributeUtil.setAttributeMarker(tAttributeRHS,
RuleUtil.TR_UNSPECIFIED);
}
// case: attribute in NAC has no marker, i.e. it has to be translated already
else{
AttributeUtil.setAttributeMarker(tAttributeRHS,
RuleUtil.Translated_Graph);
}
}
}
// case: node is in LHS
// set marker that it has to be translated already
if(tNodeLHS!=null){
// set marker in LHS, if node is in LHS (not in NAC)
setNodeMarker(ruleTNode, RuleUtil.Translated_Graph);
setNodeMarker(tNodeLHS, RuleUtil.Translated_Graph);
TAttribute newAttLHS = null;
for (Attribute attr : oldNodeRHS.getAttributes()) {
tAttributeRHS = (TAttribute) getCopiedObject(attr);
// case: attribute is created by the TGG rule
if (RuleUtil.NEW.equals(((TAttribute)attr).getMarkerType())){
newAttLHS = (TAttribute) copyAtt(attr, RuleUtil.getLHSNode((Node) tAttributeRHS.eContainer()));
AttributeUtil.setAttributeMarker(tAttributeRHS, RuleUtil.Translated);
// marker needed for matching constraint
AttributeUtil.setAttributeMarker(newAttLHS, RuleUtil.Not_Translated_Graph);
setValueOfMarkedAttributeInPreservedNode(newNode, attr,
tAttributeRHS, newAttLHS);
}
// case: attribute is not created by the TGG rule
else{
// set marker that it has to be translated already
tAttributeLHS = (TAttribute) RuleUtil.getLHSAttribute(tAttributeRHS);
AttributeUtil.setAttributeMarker(tAttributeRHS, RuleUtil.Translated_Graph);
AttributeUtil.setAttributeMarker(tAttributeLHS, RuleUtil.Translated_Graph);
}
}
}
}
}
private void setValueOfMarkedAttributeInPreservedNode(Node newNode,
Attribute oldAttribute, TAttribute tAttributeRHS, TAttribute newAttLHS) {
final LinkedHashSet<String> usedVars = new LinkedHashSet<String>();
final LinkedHashSet<String> definedVars = new LinkedHashSet<String>();
usedVars.removeAll(definedVars);//local definition override global vars
// case: node has name identifier - then replace attribute value by parameter
if (newNode.getName() != null && !newNode.getName().isEmpty() && newNode.getName().startsWith(REF_PREFIX) && (newNode.getName().charAt(0) < '0' || newNode.getName().charAt(0) > '9')){
replaceAttributeValueByStructuredName(newNode, newAttLHS,
tAttributeRHS);
} else {
// case: attribute value is an expression
if (newNode.getGraph().getRule().getParameter(oldAttribute.getValue()) == null){
// convertAttExpressionToAttCondition(newNode, oldAttribute.getValue(),
// newAttLHS, tAttributeRHS);
// TODO: conversion of attribute expressions is deactivated
}
for (Iterator<Parameter> itr = unassignedParameters.iterator(); itr.hasNext();) {
Parameter p = itr.next();
if (usedVars.contains(p.getName())){
newAttLHS.setValue(p.getName());
tAttributeRHS.setValue(p.getName());
itr.remove();
}
}
}
}
private void setValueOfMarkedAttribute(Node newNode,
TAttribute newAttLHS, TAttribute newAttRHS,
Attribute oldAttribute) {
// case: node has name identifier - then replace attribute value by parameter
if (newNode.getName() != null && !newNode.getName().isEmpty() && newNode.getName().startsWith(REF_PREFIX) && (newNode.getName().charAt(0) < '0' || newNode.getName().charAt(0) > '9')){
replaceAttributeValueByStructuredName(newNode, newAttLHS,
newAttRHS);
} else {
// case: attribute value is an expression
if (newNode.getGraph().getRule().getParameter(oldAttribute.getValue()) == null){
// convertAttExpressionToAttCondition(newNode,oldAttribute.getValue(),
// newAttLHS, newAttRHS);
// TODO: deactivated conversion of attribute expression
}
}
}
private void convertAttExpressionToAttCondition(Node newNode,
String oldAttValue, Attribute newAttLHS, TAttribute newAttRHS) {
// replace attribute value by new parameter
String parameter = getFreshParameterName("in_"+newAttRHS.getType().getName(),newNode.getGraph().getRule());
Parameter p = HenshinFactory.eINSTANCE.createParameter(parameter);
newNode.getGraph().getRule().getParameters().add(p);
newAttLHS.setValue(p.getName());
newAttRHS.setValue(p.getName());
// create attribute condition to check the value
AttributeCondition attCondition = HenshinFactory.eINSTANCE.createAttributeCondition();
attCondition.setConditionText(parameter+"=="+oldAttValue);
newNode.getGraph().getRule().getAttributeConditions().add(attCondition);
}
private void replaceAttributeValueByStructuredName(Node newNode,
TAttribute newAttLHS, TAttribute newAttRHS) {
String parameter = newNode.getName() + "_" + newAttLHS.getType().getName();
newAttLHS.setValue(parameter);
newAttRHS.setValue(parameter);
if (newNode.getGraph().getRule().getParameter(parameter) == null){
Parameter p = HenshinFactory.eINSTANCE.createParameter(parameter);
//parameter.setType(newAttLHS.getType().eClass());
newNode.getGraph().getRule().getParameters().add(p);
}
}
private String getFreshParameterName(String name,
Rule rule) {
String new_name=name;
int i=1;
while(rule.getParameter(new_name)!=null)
{
i++;
new_name=name+"_"+i;
}
return new_name;
}
@Override
public boolean filter(Node oldNode, Node newNode) {
return true;
}
}
protected class OpRuleEdgeProcessor implements EdgeProcessor {
@Override
public void process(Edge oldEdge, Edge newEdge) {
TEdge newTEdge = (TEdge) newEdge;
// case: edge is marked to be created by the TGG rule, thus it
// shall be translated by the FT rule
if (RuleUtil.NEW.equals(((TEdge) oldEdge).getMarkerType())) {
setEdgeMarker(newEdge, RuleUtil.Translated);
// LHS
Node sourceTNodeLHS = RuleUtil.getLHSNode(newEdge
.getSource());
Node targetTNodeLHS = RuleUtil.getLHSNode(newEdge
.getTarget());
// LHS
Edge tEdgeLHS = copyEdge(oldEdge, tRuleLhs);
newEdge.getGraph().getRule().getLhs().getEdges()
.add(tEdgeLHS);
tEdgeLHS.setSource(sourceTNodeLHS);
tEdgeLHS.setTarget(targetTNodeLHS);
// for matching constraint
setEdgeMarker(tEdgeLHS, RuleUtil.Not_Translated_Graph);
}
// case: edge is not created by the TGG rule
else {
// case: edge is in NAC and has an unspecified marker
if (RuleUtil.TR_UNSPECIFIED.equals(newTEdge.getMarkerType()))
newTEdge.setMarkerType(RuleUtil.TR_UNSPECIFIED);
else {
// mark the edge to be translated already
setEdgeMarker(newEdge, RuleUtil.Translated_Graph);
// handle LHS edge
TEdge tEdgeLHS = (TEdge) RuleUtil.getLHSEdge(newEdge);
if (tEdgeLHS != null)
// case: edge is in RHS graph
setEdgeMarker(tEdgeLHS, RuleUtil.Translated_Graph);
}
}
}
@Override
public boolean filter(Edge oldEdge) {
return filterNode((TNode)oldEdge.getSource()) && filterNode((TNode)oldEdge.getTarget());
}
}
private LinkedList<Parameter> unassignedParameters = new LinkedList<Parameter>();
public GenerateOpRuleCommand(Rule rule,IndependentUnit unit) {
super(rule,unit);
unassignedParameters.addAll(rule.getParameters());
for (Node node : rule.getLhs().getNodes()) {
for (Attribute attr : node.getAttributes()) {
for (Iterator<Parameter> itr = unassignedParameters.iterator(); itr.hasNext();) {
Parameter p = itr.next();
if (p.getName().equals(attr.getValue()))
{
itr.remove();
}
}
}
}
addNodeProcessors();
edgeProcessors.add(new OpRuleEdgeProcessor());
}
protected abstract void addNodeProcessors();
public IndependentUnit getContainer(IndependentUnit container){
Unit opRuleContainer;
if (container != null && !container.getName().equals(RULE_FOLDER) ){
Module m = (Module) EcoreUtil.getRootContainer(oldRule);
opRuleContainer = m.getUnit(prefix + container.getName());
if (!(opRuleContainer instanceof IndependentUnit)){
if (opRuleContainer != null){
opRuleContainer.setName(OP_RULE_CONTAINER_PREFIX + opRuleContainer.getName());
}
opRuleContainer = HenshinFactory.eINSTANCE.createIndependentUnit();
opRuleContainer.setName(prefix + container.getName());
opRuleContainer.setDescription(OP_RULES_PNG);
m.getUnits().add(opRuleContainer);
((IndependentUnit)m.getUnit(OP_RULE_FOLDER)).getSubUnits().add(opRuleContainer);
}
} else {
Module m = (Module) EcoreUtil.getRootContainer(oldRule);
opRuleContainer = m.getUnit(OP_RULE_FOLDER);
}
return (IndependentUnit) opRuleContainer;
}
protected abstract void deleteTRule(Rule tr);
@Override
protected void preProcess() {
for (Unit tr : tgg.getUnits()) {
TGGRule rule = null;
if (tr instanceof TGGRule) {
rule = (TGGRule) tr;
if (rule!=null && rule.getName().equals(prefix + oldRule.getName())) {
// there is already a TRule for this rule -> delete the old one
this.update = true;
this.oldruleIndex = tgg.getUnits().indexOf(rule);
deleteTRule(rule);
break; }
}
}
}
}