blob: 8129528e0715735aec5f69fcbcd5026106b37f7b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004-2008 Akos Horvath, Gergely Varro and Daniel Varro
* 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:
* Akos Horvath, Gergely Varro - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.algorithms;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.Vector;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.viatra2.core.IModelManager;
import org.eclipse.viatra2.gtasm.patternmatcher.ParameterMode;
import org.eclipse.viatra2.gtasm.patternmatcher.PatternCallSignature;
import org.eclipse.viatra2.gtasm.patternmatcher.exceptions.PatternMatcherCompileTimeException;
import org.eclipse.viatra2.gtasm.patternmatcher.exceptions.PatternMatcherRuntimeException;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.exceptions.GTRuleBuildingException;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.GTElementMapping;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.GTElementMappingType;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.GTOperationContext;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.GTOperationGenerator;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.DeleteModelElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.ElementManipulationOperation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.IUpdatePlanOperation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.validation.GTRuleValidator;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.EdgeType;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.MatchingFrame;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.PatternMatcherErrorStrings;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.VPMModelElementType;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.VariableID;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.callgraph.BodyNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.callgraph.DanglingVPMElementDTO;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.callgraph.FlattenedPattern;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.callgraph.PatternNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.callgraph.PatternNodeIncremental;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.callgraph.PatternReferenceNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.CheckOperation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.ISearchPlanOperation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.SearchPlanOperation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.AbstractNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.ConstantSearchGraphNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.EdgeTypeinAlgorithm;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.PatternCallSearchGraphNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.SearchGraphEdge;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.SearchGraphNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.VariableSearchGraphNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.traceability.AbstractTraceabilityElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.traceability.ConstantNodeTraceabilityElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.traceability.EdgeTraceabilityElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.traceability.NodeTraceabilityElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.traceability.PatternCallNodeTraceabilityElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.traceability.VariableNodeTraceabilityElement;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.core.AnnotatedElement;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.enums.ContainmentMode;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.terms.Constant;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.terms.Term;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.terms.VariableReference;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.ContainmentConstraint;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.GTPatternBody;
import org.eclipse.viatra2.gtasmmodel.vpm.editmodel.Entity;
import org.eclipse.viatra2.gtasmmodel.vpm.editmodel.ModelElement;
import org.eclipse.viatra2.gtasmmodel.vpm.editmodel.Relation;
import org.eclipse.viatra2.gtasmmodel.vpm.editmodel.Relationship;
import org.eclipse.viatra2.gtasmmodel.vpm.editmodel.SupertypeOf;
import org.eclipse.viatra2.gtasmmodel.vpm.editmodel.TypeOf;
import org.eclipse.viatra2.gtasmmodel.vpm.editmodel.VPMElement;
import org.eclipse.viatra2.logger.Logger;
/**A search graph implementation for the VPM models
* @author Akos Horvath
*
*/
public class VPMBasedSearchGraph implements ISearchGraph {
public static final int BELOW_WEIGHT = 40;
public static final int IN_WEIGHT = 10;
public static final int INSTANCEOF_WEIGHT = 20;
public static final int SUPERTYPE_WEIGHT = 10;
public static final int RELATION_WEIGHT = 15;
public static final int PATTERNCALLINV_WEIGHT = 4; //Must be the lowest weight !!!
public static final int PATTERNCALL_WEIGHT = 20;
public static final int PATTERNCALL_INCREMENTAL_WEIGHT = 9;
public static final int PATTERNCALL_STORAGE_INCREMENTAL_WEIGHT = 7;
private static final int VPM_ENTITY = -1;
private static final int VPM_RELATION = -2;
private static final int PATTERN_CALL_STORAGE_NODE = -3;
private static final int CONSTANTNODE_STARTING_ID = -4;
// in case the pattern has ENTITY or RELATION as Modelelement
// or in case the pattern call is a collector node,
// then they have to added to the constantnodes collection
private int constantNodesNumber = CONSTANTNODE_STARTING_ID;
/**
* The class represents the data structure for the search plan evaluation
*/
private ChuiEdmonds alg;
private TreeMap<Integer,SearchGraphNode> searchNodes;
private SearchGraphNode[] searchNodeOrder = null; //SearchGraphNode! not SearcPlanOperation!!!
private TreeMap<String,Integer> constantNodes;
private Map<SearchGraphNode,Boolean> hasOneInConstraint;
private ArrayList<DanglingVPMElementDTO> danglingElements;
private Map<AbstractNode,AbstractTraceabilityElement> traceabilityMapping;
private int constantNodeNumber = CONSTANTNODE_STARTING_ID;
public VPMBasedSearchGraph(IModelManager manager) {
this.alg = new ChuiEdmonds(manager);
this.searchNodes = new TreeMap<Integer, SearchGraphNode>();
this.constantNodes = new TreeMap<String, Integer>();
this.danglingElements = new ArrayList<DanglingVPMElementDTO>();
this.traceabilityMapping = new HashMap<AbstractNode, AbstractTraceabilityElement>();
}
public void setSearchNodes(TreeMap<Integer,SearchGraphNode> searchGraph) {
this.searchNodes = searchGraph;
}
public TreeMap<String, Integer> getConstantNodes() {
return constantNodes;
}
public TreeMap<Integer, SearchGraphNode> getSearchNodes() {
return searchNodes;
}
public int getConstantNodeNumber() {
return constantNodeNumber;
}
public SearchGraphNode getSearchNode(Integer key) {
return searchNodes.get(key);
}
public boolean containsKey(Object key) {
return searchNodes.containsKey(key);
}
private void debug(Logger logger) {
for (SearchGraphNode node : searchNodes.values()) {
logger.debug(node.getName()+" "+node.getOutgoingTreeEdgeNumber()+ " "+ node.isChecked());
for(SearchGraphEdge edge: node.getSources()) {
logger.debug(//" *****Name "+edge.getName()+" *****Type: "+edge.getVPMEdgeType()
""+" "+edge.getSourceNode().getName()+" -> "+ edge.getTargetNode().getName()+" "+edge.getWeight()+" "+edge.getOldWeight()+" "+edge.isChecked()+" "+ edge.getEdgeTypeinAlgorithm());
}
if(node.getTreeEdge() != null) {
logger.debug(" TREEEDGE "+node.getTreeEdge().getName()+" "+node.getTreeEdge().getSourceNode().getName()+" -> "+ node.getTreeEdge().getTargetNode().getName()+" "+node.getTreeEdge().getWeight()+" "+node.getTreeEdge().getOldWeight()+" "+node.getTreeEdge().isChecked());
}
}
}
// sets back the searchGraph to the beginning state
public void initSearchGraph() {
alg.init();
for (SearchGraphNode node : searchNodes.values()) {
node.setChecked(false);
node.setVirtualSearchGraphNode(null);
for (SearchGraphEdge edge : node.getSources()) {
edge.setEdgeTypeinAlgorithm(EdgeTypeinAlgorithm.FREE);
edge.setChecked(false);
edge.setWeight(edge.getOldWeight());
//alg.init();
//resets the outgoing tree edge number
node.setOutgoingTreeEdgeNumber(0);
}
node.setTreeEdge(null);
}//input parameter of a VariableSearchGraph is set by the FlattenedPattern
}
public void add(BodyNode bodyNode, FlattenedPattern result) throws PatternMatcherCompileTimeException {
GTPatternBody body = bodyNode.getBody();
// VPM nodes and edges are mapped to SearchGraphNodes
TreeIterator elements_iter = body.getPatternGraph().eAllContents();
//map the VPM relations and entites to SearchGraph nodes
while(elements_iter.hasNext()) {
Object obj = elements_iter.next();
if(obj instanceof Relation || obj instanceof Entity)
evaluateModelElement((ModelElement) obj,result,bodyNode);
}
//maps the connections of the local VPM model elements to search graph edges
elements_iter = body.getPatternGraph().eAllContents();
while(elements_iter.hasNext()) {
Object obj = elements_iter.next();
if(obj instanceof Relation)
connectElements((Relation) obj,result,bodyNode);
if(obj instanceof Relationship)
evaluateRelationship((Relationship) obj,result,bodyNode);
}
//saves the dangling relations
Iterator iter_dangling = body.getDanglingRelations().iterator();
while(iter_dangling.hasNext())
danglingElements.add(new DanglingVPMElementDTO((VPMElement)iter_dangling.next(), bodyNode));
//saves the dangling relationships
iter_dangling = body.getDanglingRelationships().iterator();
while(iter_dangling.hasNext())
danglingElements.add(new DanglingVPMElementDTO((VPMElement)iter_dangling.next(), bodyNode));
// containment
ListIterator<ContainmentConstraint> containmentConstraints = body.getContainmentConstraints().listIterator();
while(containmentConstraints.hasNext()) {
//ContainmentConstraint conCons = containmentConstraints.next();
evaluateContainmentConstraints(containmentConstraints.next(),result,bodyNode);
}
}
private void evaluateContainmentConstraints(ContainmentConstraint conCons , FlattenedPattern result, BodyNode bodyNode){
SearchGraphEdge edge = new SearchGraphEdge();
SearchGraphEdge invedge = new SearchGraphEdge();
SearchGraphNode target = getSearchNode(result.getIndex(bodyNode.getVariableID(conCons.getVariable())));
//traceability
EdgeTraceabilityElement edgeTraceability = new EdgeTraceabilityElement(edge,conCons);
traceabilityMapping.put(edge, edgeTraceability);
//inverse
EdgeTraceabilityElement inverseEdgeTraceability = new EdgeTraceabilityElement(invedge,conCons);
traceabilityMapping.put(invedge, inverseEdgeTraceability);
if(conCons.getMode() == ContainmentMode.BELOW_LITERAL) {
edge.setVPMEdgeType(EdgeType.BELOW);
edge.setOldWeight(BELOW_WEIGHT);
edge.setWeight(BELOW_WEIGHT);
invedge.setVPMEdgeType(EdgeType.BELOW);
invedge.setOldWeight(BELOW_WEIGHT*2);
invedge.setWeight(BELOW_WEIGHT*2);
} else {
edge.setVPMEdgeType(EdgeType.IN);
edge.setOldWeight(IN_WEIGHT);
edge.setWeight(IN_WEIGHT);
invedge.setVPMEdgeType(EdgeType.IN);
invedge.setOldWeight(IN_WEIGHT*2);
invedge.setWeight(IN_WEIGHT*2);
}
if(conCons.getParent() instanceof VariableReference &&
result.containsIndex(bodyNode.getVariableID(((VariableReference)conCons.getParent()).getVariable())))
{
VariableID parentID = bodyNode.getVariableID(((VariableReference)conCons.getParent()).getVariable());
VariableSearchGraphNode source;
if (searchNodes.containsKey(result.getIndex(parentID)))
{
source = (VariableSearchGraphNode) getSearchNode(result.getIndex(
parentID));
}
else
{
source = new VariableSearchGraphNode();
source.setVpmModelElementType(VPMModelElementType.ENTITY);
source.setInput(true);
source.setName(parentID.toString());
source.setId(result.getIndex(parentID));
searchNodes.put(source.getId(),source); //variablereference
//traceability
VariableNodeTraceabilityElement traceability = new VariableNodeTraceabilityElement(source,conCons.getParent());
traceabilityMapping.put(source, traceability);
}
edge.setName(conCons.getVariable().getName()+"_Containment");
edge.setTargetNode(target);
edge.setSourceNode(source);
edge.setSource(true);
target.addSource(edge);
edge.setInverseEdge(invedge);
invedge.setName(conCons.getVariable().getName()+"_ContainmentInverse");
invedge.setTargetNode(source);
invedge.setSourceNode(target);
invedge.setSource(false);
source.addSource(invedge);
} else if (conCons.getParent() instanceof Constant) {
ConstantSearchGraphNode source;
//a bit complicated...
Constant constant = ((Constant)conCons.getParent());
if(constantNodes.containsKey(constant.getValue()))
{
source = (ConstantSearchGraphNode) getSearchNode(constantNodes.get(constant.getValue()));
}
else
{
source = new ConstantSearchGraphNode();
source.setElement(constant.getValue());
source.setName(constant.getValue());
searchNodes.put(constantNodesNumber,source);
constantNodes.put(source.getName(), constantNodesNumber);
constantNodesNumber--;
//traceability
ConstantNodeTraceabilityElement traceability = new ConstantNodeTraceabilityElement(source,conCons.getParent());
traceabilityMapping.put(source, traceability);
}
edge.setName(conCons.getVariable().getName()+"_Containment");
edge.setTargetNode(target);
edge.setSourceNode(source);
edge.setSource(true);
target.addSource(edge);
} else {
// general case for the Term of the containment constraint
int index = result.addVariable(null);
CheckOperation operation =
bodyNode.getTermEvaluationOperation(result.getTermHandler(), conCons, index);
// handler.getTermEvaluationOperation(parent.pattern, currentLocation, conCons.getParent(), index);
result.addPreSearchPlanOperation(operation);
VariableSearchGraphNode source = new VariableSearchGraphNode();
source.setInput(true);
source.setVpmModelElementType(VPMModelElementType.ENTITY);
source.setName("PROCCESEDTERM_"+index);
source.setId(index);
searchNodes.put(index,source); //variablereference
//traceability
VariableNodeTraceabilityElement traceability = new VariableNodeTraceabilityElement(source,conCons.getParent());
traceabilityMapping.put(source, traceability);
edge.setName(conCons.getVariable().getName()+"_Containment");
edge.setTargetNode(target);
edge.setSourceNode(source);
edge.setSource(true);
target.addSource(edge);
}
}
private void connectElements(Relation rel, FlattenedPattern result, BodyNode bodyNode) throws PatternMatcherCompileTimeException {
SearchGraphNode source;
SearchGraphNode target;
SearchGraphNode relationnode;
String fromStr = rel.getFromStr();
String toStr = rel.getToStr();
Integer toIndex = result.getIndex(bodyNode.getVariableID(toStr));
Integer fromIndex = result.getIndex(bodyNode.getVariableID(fromStr));
Integer relIndex = result.getIndex(bodyNode.getVariableID(rel));
if(fromIndex != null
&& searchNodes.containsKey(fromIndex)) {
source = getSearchNode(fromIndex);
}
else if(constantNodes.containsKey(fromStr)) {
source = getSearchNode(constantNodes.get(fromStr));
}
else{
String[] context ={rel.getName(), rel.getFromStr()};
throw new PatternMatcherCompileTimeException(PatternMatcherErrorStrings.INTERNAL_SEARCGRAPH_RELATION_SOURCE_MISSING
,context
,rel);
}
if(toIndex != null
&& searchNodes.containsKey(toIndex)) {
target = getSearchNode(toIndex);
} else if(constantNodes.containsKey(toStr)) {
target = getSearchNode(constantNodes.get(toStr));
} else {
//TODO: if the target of the relation is missing it is a dangling relation but not contained in the DanlingRelations list :-)
// Needs to be added to the danglingElements collection
danglingElements.add(new DanglingVPMElementDTO(rel, bodyNode));
return;
// String[] context ={rel.getName()};
// throw new PatternMatcherCompileTimeException(PatternMatcherErrorStrings.INTERNAL_SEARCGRAPH_RELATION_TARGET_MISSING
// ,context
// ,rel);
}
if(relIndex != null
&& searchNodes.containsKey(relIndex)) {
relationnode = getSearchNode(relIndex);
} else if(constantNodes.containsKey(rel.getName())) {
relationnode = getSearchNode(constantNodes.get(rel.getName()));
} else {
String[] context ={rel.getName()};
throw new PatternMatcherCompileTimeException(PatternMatcherErrorStrings.INTERNAL_SEARCGRAPH_RELATION_MISSING
,context
,rel);
}
SearchGraphEdge edgeTarget = new SearchGraphEdge();
SearchGraphEdge edgeTargetinverse = new SearchGraphEdge();
SearchGraphEdge edgeSource = new SearchGraphEdge();
SearchGraphEdge edgeSourceinverse = new SearchGraphEdge();
// <--Source-- --Target-->
// Source Relation Target
// --invSource-> <-invTarget--
//Source
edgeSource.setSourceNode(relationnode);
edgeSource.setTargetNode(source);
edgeSource.setSource(true);
edgeSource.setWeight(RELATION_WEIGHT);
edgeSource.setOldWeight(RELATION_WEIGHT);
edgeSource.setVPMEdgeType(EdgeType.SOURCE);
edgeSource.setName(relationnode.getName()+"->"+source.getName());
//edgeSource.setParentinEMF(rel);
source.addSource(edgeSource);
//inverse source edge
edgeSourceinverse.setSourceNode(source);
edgeSourceinverse.setTargetNode(relationnode);
edgeSourceinverse.setSource(false);
edgeSourceinverse.setWeight(RELATION_WEIGHT);
edgeSourceinverse.setOldWeight(RELATION_WEIGHT);
edgeSourceinverse.setVPMEdgeType(EdgeType.SOURCE);
edgeSourceinverse.setName(source.getName()+"->"+relationnode.getName());
//edgeSourceinverse.setParentinEMF(rel);
relationnode.addSource(edgeSourceinverse);
edgeSource.setInverseEdge(edgeSourceinverse);
//Target
edgeTarget.setTargetNode(target);
edgeTarget.setSourceNode(relationnode);
edgeTarget.setSource(true);
edgeTarget.setWeight(RELATION_WEIGHT);
edgeTarget.setOldWeight(RELATION_WEIGHT);
edgeTarget.setVPMEdgeType(EdgeType.TARGET);
edgeTarget.setName(relationnode.getName()+"->"+target.getName());
//edgeTarget.setParentinEMF(rel);
target.addSource(edgeTarget);
//inverse Target edge
edgeTargetinverse.setTargetNode(relationnode);
edgeTargetinverse.setSourceNode(target);
edgeTargetinverse.setSource(false);
edgeTargetinverse.setWeight(RELATION_WEIGHT);
edgeTargetinverse.setOldWeight(RELATION_WEIGHT);
edgeTargetinverse.setVPMEdgeType(EdgeType.TARGET);
edgeTargetinverse.setName(target.getName()+"->"+relationnode.getName());
//edgeTargetinverse.setParentinEMF(rel);
relationnode.addSource(edgeTargetinverse);
edgeTarget.setInverseEdge(edgeTargetinverse);
//traceability
//source
EdgeTraceabilityElement sourceEdgeTraceability = new EdgeTraceabilityElement(edgeSource,rel);
traceabilityMapping.put(edgeSource, sourceEdgeTraceability);
//source inverse
EdgeTraceabilityElement sourceInverseEdgeTraceability = new EdgeTraceabilityElement(edgeSourceinverse,rel);
traceabilityMapping.put(edgeSourceinverse, sourceInverseEdgeTraceability);
//target
EdgeTraceabilityElement targetEdgeTraceability = new EdgeTraceabilityElement(edgeTarget,rel);
traceabilityMapping.put(edgeTarget, targetEdgeTraceability);
//target inverse
EdgeTraceabilityElement targetInverseEdgeTraceability = new EdgeTraceabilityElement(edgeTargetinverse,rel);
traceabilityMapping.put(edgeTargetinverse, targetInverseEdgeTraceability);
}
/** True if element is a dangling edge in the bodyNode and not contained in the alreadyProcessed list
* @param element The element to test
* @param bodyNode Body node containing the GT pattern
* @param alreadyProcessedDanglings List containing the already processed dangling edges
* @return
*/
private boolean isDangling(VPMElement element,BodyNode bodyNode, List<DanglingVPMElementDTO> alreadyProcessedDanglings) {
GTPatternBody body = bodyNode.getBody();
if(alreadyProcessedDanglings.contains(element))
return Boolean.FALSE;
Iterator iter = body.getDanglingRelations().iterator();
while(iter.hasNext())
{
TreeIterator elements_iter = ((EObject)iter.next()).eAllContents();
while(elements_iter.hasNext())
{if(elements_iter.next().equals(element))
return Boolean.TRUE;
}
}
iter = body.getDanglingRelationships().iterator();
while(iter.hasNext())
{
TreeIterator elements_iter = ((EObject)iter.next()).eAllContents();
while(elements_iter.hasNext())
{if(elements_iter.next().equals(element))
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}
/** Adds the dangling relations & relationships (and their additional relations and relationships) to the search graph
* @param danglings List of Dangling model elements
* @param result The Flattened pattern containing the resulting search graph
* @param alreadyProcessedDanglings Dangling elements already processed during the evaluation (to check circles between dangling edges)
* @throws PatternMatcherCompileTimeException
*/
private void evaluateDanglingElements(List<DanglingVPMElementDTO> danglings, FlattenedPattern result, List<DanglingVPMElementDTO> alreadyProcessedDanglings) throws PatternMatcherCompileTimeException{
ArrayList<DanglingVPMElementDTO> additionalDanglingElements = new ArrayList<DanglingVPMElementDTO>();
for(DanglingVPMElementDTO dto: danglings){
VPMElement element = dto.getElement();
BodyNode bodyNode= dto.getBodyNode();
if(element instanceof Relation)
{
evaluateModelElement((ModelElement) element,result,bodyNode);
Iterator iter= ((Relation)element).getType().iterator();
while(iter.hasNext())
{
VPMElement elem = (VPMElement)iter.next();
if(isDangling(elem,bodyNode,alreadyProcessedDanglings))
additionalDanglingElements.add(new DanglingVPMElementDTO(elem,bodyNode));
}
iter = ((Relation)element).getSuperRelationships().iterator();
while(iter.hasNext())
{
VPMElement elem = (VPMElement)iter.next();
if(isDangling(elem,bodyNode,alreadyProcessedDanglings))
additionalDanglingElements.add(new DanglingVPMElementDTO(elem,bodyNode));
}
iter = ((Relation)element).getRelationsFrom().iterator();
while(iter.hasNext())
{
VPMElement elem = (VPMElement)iter.next();
if(isDangling(elem,bodyNode,alreadyProcessedDanglings))
additionalDanglingElements.add(new DanglingVPMElementDTO(elem,bodyNode));
}
iter = ((Relation)element).getRelationsTo().iterator();
while(iter.hasNext())
{
VPMElement elem = (VPMElement)iter.next();
if(isDangling(elem,bodyNode,alreadyProcessedDanglings))
additionalDanglingElements.add(new DanglingVPMElementDTO(elem,bodyNode));
}
connectElements((Relation)element, result, bodyNode);
}
else if(element instanceof Relationship)
{
VariableID supplierID = bodyNode.getVariableID(((Relationship) element).getSupplierStr());
//supplier is a constant -> can not be unresolvable dangling relation
if (!result.containsIndex(supplierID))
{
evaluateRelationship((Relationship)element, result, bodyNode);
}
else
{
//supplier is a variable input type or not defined in the actual body
SearchGraphNode suppliernode = (VariableSearchGraphNode) getSearchNode(result.getIndex(supplierID));
//the supplier node is an unresolvable dangling element
if(suppliernode == null)
{
String[] context ={ element instanceof SupertypeOf ?"supertypeOf":"instanceOf",((Relationship)element).getSupplierStr() };
throw new PatternMatcherCompileTimeException(PatternMatcherErrorStrings.INTERNAL_SEARCGRAPH_RELATION_SOURCE_MISSING
,context
,element);
}
//it has a supplier can be processed
evaluateRelationship((Relationship)element, result, bodyNode);
}
}
else
{String[] context = {element.toString()};
throw new PatternMatcherCompileTimeException(PatternMatcherErrorStrings.INTERNAL_ERROR_DANGLING_RELATION_FAILED
,context
,element);
}
alreadyProcessedDanglings.add(dto);
}
if(additionalDanglingElements.size()!= 0)
evaluateDanglingElements(additionalDanglingElements, result, alreadyProcessedDanglings);
}
public void connectDanglingRelations(FlattenedPattern result) throws PatternMatcherCompileTimeException {
//TODO: is it possible to have a dangling edge with constant source or target node?
if(danglingElements.size()!= 0)
evaluateDanglingElements(danglingElements, result, new ArrayList<DanglingVPMElementDTO>());
}
/** Creates the corresponding SearchGraphnode with type information about the input ModelElement
* @param rel The model element that has to be added to the search graph
* @param result Container for the search graph
* @param bodyNode The body node describes the search graph that has to be built up
*/
private void evaluateModelElement(ModelElement rel, FlattenedPattern result, BodyNode bodyNode) {
SearchGraphEdge edge = null;
VariableID relID = bodyNode.getVariableID(rel);
// don't have explicit type relation, have to connect it to the Entity or relation global type
if(rel.getType().size() == 0) {
edge = new SearchGraphEdge();
edge.setVPMEdgeType(EdgeType.INSTANCEOF);
edge.setWeight(INSTANCEOF_WEIGHT*3);
edge.setOldWeight(INSTANCEOF_WEIGHT*3);
edge.setSource(true);
//traceability Information
EdgeTraceabilityElement edgeTraceability = new EdgeTraceabilityElement(edge,rel);
traceabilityMapping.put(edge, edgeTraceability);
//its an Entity
if(rel instanceof Entity) {
// have to create the entity searchGraph node
if( getSearchNode(VPM_ENTITY) == null) {
ConstantSearchGraphNode ent = new ConstantSearchGraphNode();
ent.setName("Entity");
ent.setElement(VPM_ENTITY_FQN);
searchNodes.put(VPM_ENTITY, ent);
//traceability Information
ConstantNodeTraceabilityElement traceability = new ConstantNodeTraceabilityElement(ent,rel);
//TODO what to do if it is the vpm.Entity element? Currently it is the pattern variable (rel)
traceabilityMapping.put(ent, traceability);
}
edge.setSourceNode( getSearchNode(VPM_ENTITY));
edge.setName("Entity-ins->"+rel.getName());
} else {
// have to create the Relation SearchGraph node
if( getSearchNode(VPM_RELATION) == null) {
ConstantSearchGraphNode ent = new ConstantSearchGraphNode();
ent.setName("Relation");
ent.setElement(VPM_RELATION_FQN);
searchNodes.put(VPM_RELATION, ent);
//traceability Information
ConstantNodeTraceabilityElement traceability = new ConstantNodeTraceabilityElement(ent,rel);
//TODO what to do if it is the vpm.Relation element?
traceabilityMapping.put(ent, traceability);
}
edge.setSourceNode( getSearchNode(VPM_RELATION));
edge.setName("Relation-ins->"+rel.getName());
}
}
if(result.containsIndex(relID)) {
//its a variable type element
if(!searchNodes.containsKey(result.getIndex(relID))) {
VariableSearchGraphNode node = new VariableSearchGraphNode();
node.setId(result.getIndex(relID));
node.setName(relID.getFancyName());
searchNodes.put(node.getId(),node);
//traceability
VariableNodeTraceabilityElement traceability = new VariableNodeTraceabilityElement(node,rel);
traceabilityMapping.put(node, traceability);
//create new else branch needed for every new IMOdelElement type
if(rel instanceof Entity)
node.setVpmModelElementType(VPMModelElementType.ENTITY);
if(rel instanceof Relation)
node.setVpmModelElementType(VPMModelElementType.RELATION);
if(rel.getType().size() == 0) {
edge.setTargetNode(node);
node.addSource(edge);
}
}
} else
//its a constant node
if(constantNodes.containsKey(rel.getName())) {
ConstantSearchGraphNode node = new ConstantSearchGraphNode();
node.setElement(rel.getRealElement());
node.setName(rel.getRealElement());
searchNodes.put(constantNodesNumber,node);
constantNodes.put(node.getName(), constantNodesNumber);
constantNodesNumber--;
//traceability Information
ConstantNodeTraceabilityElement traceability = new ConstantNodeTraceabilityElement(node,rel);
traceabilityMapping.put(node, traceability);
if(rel.getType().size() == 0) {
edge.setTargetNode(node);
node.addSource(edge);
}
}
}
private void evaluateRelationship(Relationship rel, FlattenedPattern result, BodyNode bodyNode) {
SearchGraphNode suppliernode = null;
SearchGraphEdge edge = new SearchGraphEdge();
SearchGraphEdge invedge = null;
//supplier
ModelElement supplier = rel.getSupplier();
String supplierName = rel.getSupplierStr();
VariableID supplierID = bodyNode.getVariableID(supplierName);
//client
ModelElement client = rel.getClient();
String clientName = rel.getClientStr();
VariableID clientID = bodyNode.getVariableID(clientName);
VariableSearchGraphNode clientnode =(VariableSearchGraphNode)searchNodes.get(result.getIndex(clientID));
if (result.containsIndex(supplierID)) {
//supplier is a variable input type or not defined in the actual body
suppliernode = (VariableSearchGraphNode) getSearchNode(result.getIndex(supplierID));
//the supplier node is a dangling element, needs to be processed later
if(suppliernode == null)
{
danglingElements.add(new DanglingVPMElementDTO(rel, bodyNode));
return;
}
} else {
// supplier is a constant
if (constantNodes.containsKey(supplierName)) {
suppliernode = getSearchNode(constantNodes.get(supplierName));
} else {
suppliernode = new ConstantSearchGraphNode();
((ConstantSearchGraphNode)suppliernode).setElement(supplier.getRealElement());
suppliernode.setName(((ConstantSearchGraphNode)suppliernode).getElement());
searchNodes.put(constantNodesNumber,suppliernode);
constantNodes.put(suppliernode.getName(), constantNodesNumber);
constantNodesNumber--;
//Traceability
ConstantNodeTraceabilityElement traceability = new ConstantNodeTraceabilityElement((ConstantSearchGraphNode)suppliernode,supplier);
traceabilityMapping.put(suppliernode, traceability);
}
}
if (rel instanceof TypeOf) {
edge.setVPMEdgeType(EdgeType.INSTANCEOF);
edge.setTargetNode(clientnode);
edge.setWeight(INSTANCEOF_WEIGHT);
edge.setOldWeight(INSTANCEOF_WEIGHT);
edge.setSource(true);
edge.setSourceNode(suppliernode);
edge.setName(suppliernode.getName()+"_instanceof_"+clientnode.getName());
clientnode.addSource(edge);
//inverse of instanceof
if (suppliernode instanceof VariableSearchGraphNode) {
invedge = new SearchGraphEdge();
invedge.setVPMEdgeType(EdgeType.INSTANCEOF);
invedge.setTargetNode(suppliernode);
invedge.setWeight(INSTANCEOF_WEIGHT*2);
invedge.setOldWeight(INSTANCEOF_WEIGHT*2);
invedge.setSource(false);
invedge.setSourceNode(clientnode);
invedge.setName(suppliernode.getName()+"_instanceofINV_"+clientnode.getName());
suppliernode.addSource(invedge);
edge.setInverseEdge(invedge);
//traceability inverse
EdgeTraceabilityElement inverseEdgeTraceability = new EdgeTraceabilityElement(invedge,rel);
traceabilityMapping.put(invedge, inverseEdgeTraceability);
}
} else {
edge.setVPMEdgeType(EdgeType.SUPERTYPEOF);
edge.setTargetNode(suppliernode);
edge.setSourceNode(clientnode);
edge.setSource(true);
edge.setWeight(SUPERTYPE_WEIGHT);
edge.setOldWeight(SUPERTYPE_WEIGHT);
edge.setName(suppliernode.getName()+"_supertypeof_"+clientnode.getName());
//edge.setParentinEMF(rel);
suppliernode.addSource(edge);
//inverse
invedge = new SearchGraphEdge();
invedge.setVPMEdgeType(EdgeType.SUPERTYPEOF);
invedge.setTargetNode(clientnode);
invedge.setSourceNode(suppliernode);
invedge.setSource(false);
invedge.setWeight(SUPERTYPE_WEIGHT*2);
invedge.setOldWeight(SUPERTYPE_WEIGHT*2);
invedge.setName(suppliernode.getName()+"_supertypeof_INV"+clientnode.getName());
clientnode.addSource(invedge);
edge.setInverseEdge(invedge);
//inverse relationship traceability
EdgeTraceabilityElement inverseEdgeTraceability = new EdgeTraceabilityElement(invedge,rel);
traceabilityMapping.put(invedge, inverseEdgeTraceability);
}
//relationship traceability
EdgeTraceabilityElement edgeTraceability = new EdgeTraceabilityElement(edge,rel);
traceabilityMapping.put(edge, edgeTraceability);
}
public void add(PatternReferenceNode prNode, FlattenedPattern result) throws PatternMatcherCompileTimeException {
final PatternNode reference = prNode.getReference();
final List<Term> actualParameters = prNode.getActualParameters();
final BodyNode parent = (BodyNode) prNode.getParent();
int weight = PATTERNCALL_WEIGHT;
//the parameter order of the pattern call mapped to the id values of the searchGraphNodes
Integer[] parameterMapping = new Integer[actualParameters.size()];
//The pattern call node
PatternCallSearchGraphNode patternCallNode = new PatternCallSearchGraphNode();
int index = result.addVariable(null);
patternCallNode.setName("PatternCallof_"+reference.getPattern().getName());
patternCallNode.setId(index);
patternCallNode.setVpmModelElementType(VPMModelElementType.OPERATION);
patternCallNode.setPatternNode(reference);
searchNodes.put(patternCallNode.getId(),patternCallNode);
//traceability pattern call
PatternCallNodeTraceabilityElement patternCallTraceabilityElement= new PatternCallNodeTraceabilityElement(patternCallNode,prNode.getPatternCall());
traceabilityMapping.put(patternCallNode, patternCallTraceabilityElement);
//if it is an incrementally matched pattern call new weigh values are set and it is attached to the Storage node
if(prNode.getReference() instanceof PatternNodeIncremental)
{//TODO: traceability of the storage node and its edge? Is it needed?
weight = PATTERNCALL_INCREMENTAL_WEIGHT;
SearchGraphEdge edge = null;
edge = new SearchGraphEdge();
edge.setVPMEdgeType(EdgeType.PATTERN_CALL_STORAGE);
edge.setWeight(PATTERNCALL_STORAGE_INCREMENTAL_WEIGHT);
edge.setOldWeight(PATTERNCALL_STORAGE_INCREMENTAL_WEIGHT);
edge.setSource(true);
// have to create the Storage node
if( getSearchNode(PATTERN_CALL_STORAGE_NODE) == null) {
ConstantSearchGraphNode ent = new ConstantSearchGraphNode();
ent.setName("Pattern_Call_Storage_Node");
ent.setElement(VPM_ENTITY_FQN);
searchNodes.put(PATTERN_CALL_STORAGE_NODE, ent);
}
//sets the target and the source nodes
edge.setSourceNode( getSearchNode(PATTERN_CALL_STORAGE_NODE));
edge.setName("PatternStorage-store->"+patternCallNode.getName());
edge.setTargetNode(patternCallNode);
patternCallNode.addSource(edge);
}
//connecting the variables to the pattern call
for (int i = 0; i < actualParameters.size(); i++) {
if (actualParameters.get(i) instanceof VariableReference) {
VariableReference varRef= (VariableReference) actualParameters.get(i);
SearchGraphNode inputNode = null;
//the node is already processed in the flattened pattern
Integer variableIndex = result.getIndex(parent.getVariableID(varRef.getVariable()));
if (searchNodes.containsKey(variableIndex)) {
inputNode = getSearchNode(variableIndex);
parameterMapping[i] = ((VariableSearchGraphNode)inputNode).getId();
} else {
// new search graph node only used in the pattern call!
inputNode = new VariableSearchGraphNode();
int id;
inputNode.setName(parent.getVariableID(varRef.getVariable()).toString());
//recursive pattern matching call
if (result.getIndex(parent.getVariableID(varRef.getVariable())) != null) {
//the parameter is passed through the pattern
//already has an index
id = result.getIndex(parent.getVariableID(varRef.getVariable()));
} else{
//new id
id = result.addVariable(parent.getVariableID(varRef.getVariable()));
}
((VariableSearchGraphNode)inputNode).setId(id);
searchNodes.put(((VariableSearchGraphNode)inputNode).getId(), inputNode);
parameterMapping[i] = id;
//traceability
VariableNodeTraceabilityElement traceability = new VariableNodeTraceabilityElement((VariableSearchGraphNode) inputNode,varRef);
traceabilityMapping.put(inputNode, traceability);
//System.out.println("Pattern Call inside GT pattern with through-passed variables");
}
//connects the pattern node to its input parameter nodes
SearchGraphEdge edgePatternCall = new SearchGraphEdge();
SearchGraphEdge edgePatternCallinverse = new SearchGraphEdge();
// <--PatternCall--
// Input Variable Pattern Call
// --PatternCallinverse->
//pattern call edge
edgePatternCall.setSourceNode(inputNode);
edgePatternCall.setTargetNode(patternCallNode);
edgePatternCall.setSource(true);
edgePatternCall.setWeight(weight);
edgePatternCall.setOldWeight(weight);
edgePatternCall.setVPMEdgeType(EdgeType.PATTERN_CALL_PARAMETER);
edgePatternCall.setName(inputNode.getName()+"->"+patternCallNode.getName());
//edgeSource.setParentinEMF();
patternCallNode.addSource(edgePatternCall);
//inverse pattern call edge
edgePatternCallinverse.setSourceNode(patternCallNode);
edgePatternCallinverse.setTargetNode(inputNode);
edgePatternCallinverse.setSource(false);
edgePatternCallinverse.setWeight(PATTERNCALLINV_WEIGHT);
edgePatternCallinverse.setOldWeight(PATTERNCALLINV_WEIGHT);
edgePatternCallinverse.setVPMEdgeType(EdgeType.PATTERN_CALL_PARAMETER);
edgePatternCallinverse.setName(patternCallNode.getName()+"->"+inputNode.getName());
//edgeSourceinverse.setParentinEMF(rel);
inputNode.addSource(edgePatternCallinverse);
edgePatternCall.setInverseEdge(edgePatternCallinverse);
//traceability edge
EdgeTraceabilityElement edgeTraceability = new EdgeTraceabilityElement(edgePatternCall,varRef);
traceabilityMapping.put(edgePatternCall, edgeTraceability);
//traceability edge
EdgeTraceabilityElement inverseEdgeTraceability = new EdgeTraceabilityElement(edgePatternCallinverse,varRef);
traceabilityMapping.put(edgePatternCallinverse, inverseEdgeTraceability);
} else {
String[] context = {""+i, prNode.getPatternCall().getCalledPattern().getName()};
PatternMatcherCompileTimeException e = new PatternMatcherCompileTimeException(PatternMatcherErrorStrings.ILLEGAL_INPUT_PARAMETER
,context
,actualParameters.get(i));
throw e;
}
}
patternCallNode.setInputParameterMapping(parameterMapping);
}
public GTOperationContext generateGTOperations(Collection<GTElementMapping> gtElementMappings
,IModelManager manager
,PatternCallSignature[] signatures)
throws GTRuleBuildingException {
initSearchGraph();
ArrayList<IUpdatePlanOperation> manipulationOperations = new ArrayList<IUpdatePlanOperation>();
ArrayList<ISearchPlanOperation> checkSet = new ArrayList<ISearchPlanOperation>();
Collection<IUpdatePlanOperation> postSearchPlanOperations = new Vector<IUpdatePlanOperation>();
ElementManipulationOperation operation = null;
hasOneInConstraint = new HashMap<SearchGraphNode, Boolean>();
//Adds the to delete input variables to the manipulation operation plan
if(gtElementMappings != null)
for(GTElementMapping map: gtElementMappings)
//have to keep the element
if(searchNodes.containsKey(map.getRhsInputOrderIndex()))
{map.setMappingType(GTElementMappingType.KEEP);
//all mapped elements are input parameters for the RHS
((VariableSearchGraphNode) getSearchNode(map.getRhsInputOrderIndex())).setInput(true);
((VariableSearchGraphNode) getSearchNode(map.getRhsInputOrderIndex())).setChecked(true);
}
else//have to delete the element
{
map.setMappingType(GTElementMappingType.DEL);
manipulationOperations.add(new DeleteModelElement(manager, map.getRhsInputOrderIndex()));
}
// All input parameter specific operations + Check set are generated
for (int j = 0; j < signatures.length; j++) {
if (searchNodes.containsKey(j) && getSearchNode(j) instanceof VariableSearchGraphNode) {
VariableSearchGraphNode node = (VariableSearchGraphNode) getSearchNode(j);
if(signatures[j].getParameterMode().equals(ParameterMode.INPUT)) {
{node.setInput(true);
Collection<IUpdatePlanOperation> _temp= GTOperationGenerator.getInputSpecificOperation(node,manager,checkSet);
if(_temp != null && _temp.size() > 0)
postSearchPlanOperations.addAll(_temp);
}
} else {
node.setInput(false);
}
}
}
//generateInit(inputMapping, signature, template,manager, gtElementMappings);
searchNodeOrder = alg.evaluateSearchPlan(this);
//boolean hasINConstraint = false;
for(SearchGraphNode node : searchNodeOrder) {
if(node instanceof ConstantSearchGraphNode) {
node.setChecked(true);
}
GTRuleValidator.validateContainment(node, manager,hasOneInConstraint);
//all not mapped variable search graph node have to be created
if((!node.isChecked()) && node.getTreeEdge() != null
&& (!node.getTreeEdge().isChecked())) {
operation = GTOperationGenerator.getModelManipulationOperation((VariableSearchGraphNode)node, manager,checkSet,this);
if(operation!= null) {
//operation.toString();
manipulationOperations.add(operation);
}
}
//edges that have to be created
for(SearchGraphEdge edge: node.getSources()) {
if(edge.getSourceNode().isChecked() && edge.getTargetNode().isChecked() && !edge.isChecked()) {
operation = GTOperationGenerator.getModelManipulationOperation(edge, manager,checkSet,this);
if(operation!= null) {
//operation.toString();
manipulationOperations.add(operation);
}
}
}
}
// have to check if there are unchecked element in the searchGraph (they must be created or simply checked)
boolean noUncheckedOperation = true;
do {
noUncheckedOperation = true;
for(SearchGraphNode node : searchNodeOrder) {
if(!node.isChecked()) {
//System.out.println("Node: "+node.getName());
operation = GTOperationGenerator.getModelManipulationOperation((VariableSearchGraphNode)node, manager , checkSet,this);
if(operation == null)
{noUncheckedOperation = false;}
else {
manipulationOperations.add(operation);
node.setChecked(true);
}
}
//edge checking
for(SearchGraphEdge edge : node.getSources())
if(!edge.isChecked()
&& edge.getSourceNode().isChecked()
&& edge.getTargetNode().isChecked())
{operation = GTOperationGenerator.getModelManipulationOperation(edge, manager, checkSet,this);
//System.out.println("Edge: "+node.getName());
if(operation == null)
{noUncheckedOperation = false;}
else
{
manipulationOperations.add(operation);
edge.setChecked(true);
}
}
}
} while(!noUncheckedOperation);
if(postSearchPlanOperations != null && postSearchPlanOperations.size() != 0)
manipulationOperations.addAll(postSearchPlanOperations);
GTRuleValidator gtRuleValidator = new GTRuleValidator();
gtRuleValidator.validateOperationPlan(manipulationOperations,checkSet,gtElementMappings,this);
return new GTOperationContext(null,manipulationOperations,checkSet);
}
public Collection<SearchPlanOperation> generateSearchPlan(FlattenedPattern pattern, Boolean[] adornment, IModelManager manager) throws PatternMatcherRuntimeException{
// Search graph initialization and search plan generation
for (int j = 0; j < adornment.length; j++) {
SearchGraphNode node = getSearchNode(j);
if (node instanceof VariableSearchGraphNode) {
((VariableSearchGraphNode) node).setInput(adornment[j]);
}
}
searchNodeOrder= alg.evaluateSearchPlan(pattern.getSearchGraph());
return VPMPatternOperationGenerator.evaluateVPMOperationPlan(searchNodeOrder, new MatchingFrame(pattern),manager);
}
public AnnotatedElement getGTASMRepresentation(AbstractNode node) {
return node.getTraceabilityElement().getRepresentativeEMFElement();
}
public void addTraceabilityElement(SearchGraphEdge edge, EdgeTraceabilityElement element){
traceabilityMapping.put(edge, element);
}
public void addTraceabilityElement(SearchGraphNode node, NodeTraceabilityElement element){
traceabilityMapping.put(node, element);
}
}