blob: c6118256b66ae377943deb51f98c2d5e299fc821 [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.gtmatcher.validation;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.viatra2.core.IModelManager;
import org.eclipse.viatra2.core.IRelation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.exceptions.GTErrorStrings;
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.operation.CreateElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.CreateEntity;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.CreateRelationBound2Bound;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.CreateRelationBound2Constant;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.CreateRelationConstant2Bound;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.CreateRelationConstant2Constant;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.DeleteModelElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.IUpdatePlanOperation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.MoveBoundunderBound;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.MoveElement;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.SetRelation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.SetRelationSource;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.gtmatcher.internal.operation.SetRelationTarget;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.EdgeType;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.algorithms.ISearchGraph;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.operation.ISearchPlanOperation;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.ConstantSearchGraphNode;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.SearchGraphEdge;
import org.eclipse.viatra2.gtasm.patternmatcher.impl.patternmatcher.internal.searchgraph.SearchGraphNode;
/** Encapsulates GT Rule validating operations
* @author Akos Horvath
*
*/
public class GTRuleValidator {
private Map<Integer,GTValidationElement> validationElements;
public GTRuleValidator(){
validationElements = new HashMap<Integer, GTValidationElement>();
}
private GTValidationElement getValidationElement(Integer i){
if(!validationElements.containsKey(i))
validationElements.put(i, new GTValidationElement());
return validationElements.get(i);
}
/** Adds a collection to the validation process
* @param operations The collection of operations to add for the validation
*/
public void addElements(Collection<IUpdatePlanOperation> operations){
for(IUpdatePlanOperation op: operations)
addElement(op);
}
/** Adds an operation to the validation process
* @param operation The operation to add for the validation
*/
private void addElement(IUpdatePlanOperation operation){
if(operation instanceof CreateElement)
{
if(operation instanceof CreateEntity)
getValidationElement(((CreateEntity)operation).getVariableIndex()).addCreateOperation(((CreateEntity)operation));
else
if (operation instanceof CreateRelationBound2Bound)
{getValidationElement(((CreateRelationBound2Bound)operation).getVariableIndex()).addCreateOperation(((CreateRelationBound2Bound)operation));
getValidationElement(((CreateRelationBound2Bound)operation).getTarget()).addRelatedCreateOperation(((CreateRelationBound2Bound)operation));
getValidationElement(((CreateRelationBound2Bound)operation).getSource()).addRelatedCreateOperation(((CreateRelationBound2Bound)operation));
}
else if (operation instanceof CreateRelationBound2Constant)
{getValidationElement(((CreateRelationBound2Constant)operation).getVariableIndex()).addCreateOperation(((CreateRelationBound2Constant)operation));
getValidationElement(((CreateRelationBound2Constant)operation).getSource()).addRelatedCreateOperation(((CreateRelationBound2Constant)operation));
}
else if (operation instanceof CreateRelationConstant2Bound)
{getValidationElement(((CreateRelationConstant2Bound)operation).getVariableIndex()).addCreateOperation(((CreateRelationConstant2Bound)operation));
getValidationElement(((CreateRelationConstant2Bound)operation).getTarget()).addRelatedCreateOperation(((CreateRelationConstant2Bound)operation));
}
else if (operation instanceof CreateRelationConstant2Constant)
getValidationElement(((CreateRelationConstant2Constant)operation).getVariableIndex()).addCreateOperation(((CreateRelationConstant2Constant)operation));
//Relationship operations are currently not used in the process
}
else if(operation instanceof DeleteModelElement)
getValidationElement(((DeleteModelElement)operation).getVariableIndex()).addDelOperation(((DeleteModelElement)operation));
else if(operation instanceof MoveElement)
{
getValidationElement(((MoveElement)operation).getVariableIndex()).addMoveOperation(((MoveElement)operation));
if(operation instanceof MoveBoundunderBound)
getValidationElement(((MoveBoundunderBound)operation).getContainer()).addRelatedMoveOperation(((MoveElement)operation));
}
else if(operation instanceof SetRelation)
{
getValidationElement(((SetRelation)operation).getRelation()).addSetOperation(((SetRelation)operation));
//source and target of the operation
//if(operation instanceof SetRelationSource)
// getValidationElement(((SetRelationSource)operation).getSource()).addSetOperation(((SetRelation)operation));
//if(operation instanceof SetRelationTarget)
// getValidationElement(((SetRelationTarget)operation).getTarget()).addSetOperation(((SetRelation)operation));
}
}
/**Simple validation algorithm on the input searchgraph
* @param searchGraph
* @throws GTRuleBuildingException
*/
private void basicValidation(ISearchGraph searchGraph) throws GTRuleBuildingException{
// on all elements simple checks
for(Map.Entry<Integer, GTValidationElement> entry: validationElements.entrySet()){
GTValidationElement element = entry.getValue();
//basic operation checks
if(element.getDelOperations().size()>1)
{
String[] context = {searchGraph.getSearchNode(entry.getKey()).getName()};
throw new GTRuleBuildingException(GTErrorStrings.GTVALIDATION_MORE_THANONE_DEL
,context
,searchGraph.getGTASMRepresentation(searchGraph.getSearchNode(entry.getKey())));
}
if(element.getCreateOperations().size()>1)
{
String[] context = {searchGraph.getSearchNode(entry.getKey()).getName()};
throw new GTRuleBuildingException(GTErrorStrings.GTVALIDATION_MORE_THANONE_CREATE
,context
,searchGraph.getGTASMRepresentation(searchGraph.getSearchNode(entry.getKey())));
}
if(element.getDelOperations().size() == 1
&&
(element.createOperations.size() != 0
|| element.moveOperations.size() != 0
|| element.setOperations.size() != 0))
{
String[] context = {searchGraph.getSearchNode(entry.getKey()).getName()
,""+element.createOperations.size()
,""+element.moveOperations.size()
,""+element.setOperations.size()};
throw new GTRuleBuildingException(GTErrorStrings.GTVALIDATION_DEL_AND_OTHEROPERATION
,context
,searchGraph.getGTASMRepresentation(searchGraph.getSearchNode(entry.getKey())));
}
//it has to be deleted but also used in a relation/relationship/move/set create operation as a target or source of the relation
if((element.getRelatedCreateOperations().size() > 0
|| element.getRelatedMoveOperations().size() > 0
|| element.getRelatedSetOperations().size() >0)
&&
(element.getDelOperations().size() == 1))
{
String[] context = {searchGraph.getSearchNode(entry.getKey()).getName()};
throw new GTRuleBuildingException(GTErrorStrings.GTVALIDATION_DEL_AND_USED
,context
,searchGraph.getGTASMRepresentation(searchGraph.getSearchNode(entry.getKey())));
}
}
}
private void gtElementMappingValidation( Collection<GTElementMapping> elementMappings,
Collection<ISearchPlanOperation> checkSet, ISearchGraph searchGraph) throws GTRuleBuildingException{
//searchGraph.getGTASMRepresentation(searchGraph.get(2));
for(GTElementMapping mapping: elementMappings){
GTValidationElement element = null;
if(!validationElements.containsKey(mapping.getRhsInputOrderIndex()))
continue;
element= validationElements.get(mapping.getRhsInputOrderIndex());
if(mapping.getMappingType().equals(GTElementMappingType.KEEP)){
if(element.getDelOperations().size() != 0)
{
String[] context = {searchGraph.getSearchNode(mapping.getRhsInputOrderIndex()).getName()};
throw new GTRuleBuildingException(GTErrorStrings.GTVALIDATION_KEEP_DEL
,context
,searchGraph.getGTASMRepresentation(searchGraph.getSearchNode(mapping.getRhsInputOrderIndex())));
}
}
else
if(element.getDelOperations().size() != 1)
{
String[] context = {searchGraph.getSearchNode(mapping.getRhsInputOrderIndex()).getName()};
throw new GTRuleBuildingException(GTErrorStrings.INTERNAL_GTVALIDATION_NOT_DELETED
,context
,searchGraph.getGTASMRepresentation(searchGraph.getSearchNode(mapping.getRhsInputOrderIndex())));
}
//more then one set operation on the same relation
if(element.getSetOperations().size() > 1){
int to=0,from=0;
for(SetRelation setR: element.getSetOperations())
{
if(setR instanceof SetRelationSource)
from++;
else if(setR instanceof SetRelationTarget)
to++;
}
if(to==1 && from >1)
{
String[] context = {searchGraph.getSearchNode(mapping.getRhsInputOrderIndex()).getName()};
throw new GTRuleBuildingException(GTErrorStrings.GTVALIDATION_SET_SOURCE
,context
,searchGraph.getGTASMRepresentation(searchGraph.getSearchNode(mapping.getRhsInputOrderIndex())));
}
if(to>1 && from == 1)
{
String[] context = {searchGraph.getSearchNode(mapping.getRhsInputOrderIndex()).getName()};
throw new GTRuleBuildingException(GTErrorStrings.GTVALIDATION_SET_TARGET
,context
,searchGraph.getGTASMRepresentation(searchGraph.getSearchNode(mapping.getRhsInputOrderIndex())));
}
if(to>1 && from > 1)
{
String[] context = {searchGraph.getSearchNode(mapping.getRhsInputOrderIndex()).getName()};
throw new GTRuleBuildingException(GTErrorStrings.GTVALIDATION_SET_BOTH
,context
,searchGraph.getGTASMRepresentation(searchGraph.getSearchNode(mapping.getRhsInputOrderIndex())));
}
}
}
}
/** Validates the search plan for multiple del, set, create etc. operations on a single element
* @param nonchangeableGTOperations The operations to be checked
* @param checkSet the check set that contains additional check operation on elements
* @param elementMappings The element mapping between the LHS nad the RHS
* @param searchGraph The search graph
* @throws GTRuleBuildingException
*/
public void validateOperationPlan(Collection<IUpdatePlanOperation> nonchangeableGTOperations
, Collection<ISearchPlanOperation> checkSet
, Collection<GTElementMapping> elementMappings, ISearchGraph searchGraph) throws GTRuleBuildingException{
addElements(nonchangeableGTOperations);
basicValidation(searchGraph);
gtElementMappingValidation(elementMappings,checkSet,searchGraph);
}
/** Validates the containment related elements between entities
* @param node The node to be checked
* @param manager The model space manager
* @param hasOneInConstraint The global 'IN' type constraint store for the input elements
* @throws GTRuleBuildingException
*/
public static void validateContainment(SearchGraphNode node, IModelManager manager, Map<SearchGraphNode, Boolean> hasOneInConstraint) throws GTRuleBuildingException {
for(SearchGraphEdge edge: node.getSources()){
//direct IN constraints on the node
if(edge.getVPMEdgeType().equals(EdgeType.IN) && edge.isSource())
//&& edge.isChecked()
if(hasOneInConstraint.get(node) != null && hasOneInConstraint.get(node))
// two IN constraints on the element
{ String[] context = {node.getName()};
throw new GTRuleBuildingException(GTErrorStrings.MORE_ONE_IN_CONTAINMENT
,context
,node.getTraceabilityElement().getRepresentativeEMFElement());
}
else
hasOneInConstraint.put(node, Boolean.TRUE);
//edges that are aggregations
if(edge.getVPMEdgeType().equals(EdgeType.TARGET) && edge.isSource())
{
SearchGraphNode edgeNode = edge.getSourceNode();
for(SearchGraphEdge typeEdge: edgeNode.getSources())
{
if(typeEdge.getVPMEdgeType().equals(EdgeType.INSTANCEOF) && edge.getSourceNode() instanceof ConstantSearchGraphNode && edge.isSource())
{
String fqn = ((ConstantSearchGraphNode)edge.getSourceNode()).getElement();
//it can be a relation type
if(fqn != null && !fqn.equals(ISearchGraph.VPM_ENTITY_FQN) && !fqn.equals(ISearchGraph.VPM_RELATION_FQN))
{ IRelation relation = manager.getRelationByName(fqn);
if(relation != null && relation.getIsAggregation())
{
if(hasOneInConstraint.get(node) != null && hasOneInConstraint.get(node))
{ String[] context = {node.getName()};
throw new GTRuleBuildingException(GTErrorStrings.MORE_ONE_IN_CONTAINMENT
,context
,node.getTraceabilityElement().getRepresentativeEMFElement());
}
else
hasOneInConstraint.put(node, Boolean.TRUE);
}
}
}
}
}
}
}
}