| /******************************************************************************* |
| * 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); |
| } |
| } |
| } |
| } |
| } |
| } |
| }
|
| |
| }
|
|
|