/** * Copyright (c) 2012-2016 Marsha Chechik, Alessio Di Sandro, Michalis Famelis, * Rick Salay. * 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: * Alessio Di Sandro - Implementation. */ package edu.toronto.cs.se.modelepedia.mavo.operator.slice; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.jdt.annotation.NonNull; import edu.toronto.cs.se.mavo.MAVOElement; import edu.toronto.cs.se.mmint.MMINTException; import edu.toronto.cs.se.mmint.java.reasoning.IJavaOperatorInputConstraint; import edu.toronto.cs.se.mmint.MIDTypeHierarchy; import edu.toronto.cs.se.mmint.mavo.mavomid.MAVOModelElementReference; import edu.toronto.cs.se.mmint.mid.GenericElement; import edu.toronto.cs.se.mmint.mid.MID; import edu.toronto.cs.se.mmint.mid.MIDLevel; import edu.toronto.cs.se.mmint.mid.Model; import edu.toronto.cs.se.mmint.mid.ModelElement; import edu.toronto.cs.se.mmint.mid.operator.impl.OperatorImpl; import edu.toronto.cs.se.mmint.mid.reasoning.MIDConstraintChecker; import edu.toronto.cs.se.mmint.mid.relationship.BinaryModelRel; import edu.toronto.cs.se.mmint.mid.relationship.Mapping; import edu.toronto.cs.se.mmint.mid.relationship.MappingReference; import edu.toronto.cs.se.mmint.mid.relationship.ModelElementEndpoint; import edu.toronto.cs.se.mmint.mid.relationship.ModelElementEndpointReference; import edu.toronto.cs.se.mmint.mid.relationship.ModelElementReference; import edu.toronto.cs.se.mmint.mid.relationship.ModelEndpointReference; import edu.toronto.cs.se.mmint.mid.relationship.ModelRel; import edu.toronto.cs.se.mmint.mid.utils.MIDRegistry; public class ChangeImpact extends OperatorImpl { public static class InputConstraint implements IJavaOperatorInputConstraint { @Override public boolean isAllowedInput(Map<String, Model> inputsByName) { //TODO MMINT[OPERATOR] Check that diff and trace share a model return true; } } // input-output private final static @NonNull String IN_MODELREL1 = "diff"; private final static @NonNull String IN_MODELREL2 = "trace"; private final static @NonNull String OUT_MODELREL = "impact"; // constants private final static String SRC_MODELELEMENDPOINT_NAME = "diff"; private final static String TGT_MODELELEMENDPOINT_NAME = "impacted"; private void createOrigVarTables(ModelEndpointReference modelEndpointRef, Map<String, List<ModelElementReference>> unifyTable, Map<String, List<MAVOModelElementReference>> typeTable) { // O(n) + O(m i log i), O(n) best case when m=n and i=1, O(n log n) worst case when m=1 and i=n // type table for (ModelElementReference modelElemRef : modelEndpointRef.getModelElemRefs()) { // O(n) String modelElemTypeUri = modelElemRef.getObject().getMetatypeUri(); List<MAVOModelElementReference> unifiablesFromSameType = typeTable.get(modelElemTypeUri); if (unifiablesFromSameType == null) { unifiablesFromSameType = new ArrayList<>(); typeTable.put(modelElemTypeUri, unifiablesFromSameType); } unifiablesFromSameType.add((MAVOModelElementReference) modelElemRef); } // merge table for (List<MAVOModelElementReference> unifiablesFromSameType : typeTable.values()) { // + O(m), m<=n for (ModelElementReference modelElemRef : unifiablesFromSameType) { List<ModelElementReference> unifiables = new ArrayList<>(); unifyTable.put(modelElemRef.getUri(), unifiables); unifiables.add(modelElemRef); } for (int i = 0; i < unifiablesFromSameType.size(); i++) { // * O(i), i<=n, SUM(i_k)=n for k=0..m MAVOModelElementReference modelElemRef = unifiablesFromSameType.get(i); List<ModelElementReference> unifiables = unifyTable.get(modelElemRef.getUri()); for (int j = i+1; j < unifiablesFromSameType.size(); j++) { // * O(log i) MAVOModelElementReference modelElemRef2 = unifiablesFromSameType.get(j); List<ModelElementReference> unifiables2 = unifyTable.get(modelElemRef2.getUri()); if (modelElemRef.getObject().isVar() || modelElemRef2.getObject().isVar()) { unifiables.add(modelElemRef2); unifiables2.add(modelElemRef); } } } } //TODO smart check to reduce average complexity, if in same container in src model } private void createImpactedVarTables(ModelEndpointReference modelEndpointRef, Map<String, List<EObject>> unifyTable, Map<String, List<EObject>> typeTable) throws MMINTException { // type table Model model = modelEndpointRef.getObject().getTarget(); for (ModelElement modelElemType : model.getMetatype().getModelElems()) { List<EObject> unifiablesFromSameType = new ArrayList<EObject>(); typeTable.put(modelElemType.getUri(), unifiablesFromSameType); } TreeIterator<EObject> iterator = model.getEMFInstanceRoot().eAllContents(); while (iterator.hasNext()) { EObject modelEObject = iterator.next(); if (!(modelEObject instanceof MAVOElement)) { continue; } ModelElement modelElemType = MIDConstraintChecker.getAllowedModelElementType(modelEndpointRef, modelEObject); if (modelElemType == null) { continue; } List<EObject> unifiablesFromSameType = typeTable.get(modelElemType.getUri()); unifiablesFromSameType.add(modelEObject); } // merge table for (List<EObject> unifiablesFromSameType : typeTable.values()) { for (EObject modelEObject : unifiablesFromSameType) { List<EObject> unifiables = new ArrayList<EObject>(); String modelEObjectUri = MIDRegistry.getModelAndModelElementUris(modelEObject, MIDLevel.INSTANCES)[1]; unifyTable.put(modelEObjectUri, unifiables); unifiables.add(modelEObject); } for (int i = 0; i < unifiablesFromSameType.size(); i++) { EObject modelEObject = unifiablesFromSameType.get(i); String modelEObjectUri = MIDRegistry.getModelAndModelElementUris(modelEObject, MIDLevel.INSTANCES)[1]; List<EObject> unifiables = unifyTable.get(modelEObjectUri); for (int j = i+1; j < unifiablesFromSameType.size(); j++) { EObject modelEObject2 = unifiablesFromSameType.get(j); String modelEObjectUri2 = MIDRegistry.getModelAndModelElementUris(modelEObject2, MIDLevel.INSTANCES)[1]; List<EObject> unifiables2 = unifyTable.get(modelEObjectUri2); if ((((MAVOElement) modelEObject).isVar() || ((MAVOElement) modelEObject2).isVar())) { unifiables.add(modelEObject2); unifiables2.add(modelEObject); } } } } //TODO smart check to reduce average complexity, if in same container in src model } private void addImpactedModelElementReferences(ModelElementReference origModelElemRef, ModelEndpointReference impactedModelEndpointRef, MappingReference impactMappingRef, Map<String, List<EObject>> impactedUnifyTable) throws MMINTException { if (origModelElemRef.getModelElemEndpointRefs().isEmpty()) { return; } String origModelUri = ((ModelEndpointReference) origModelElemRef.eContainer()).getTargetUri(); ModelElementEndpoint rootModelElemTypeEndpoint = MIDTypeHierarchy.getRootModelElementTypeEndpoint(); for (ModelElementEndpointReference origModelElemEndpointRef : origModelElemRef.getModelElemEndpointRefs()) { MappingReference traceMappingRef = (MappingReference) origModelElemEndpointRef.eContainer(); for (ModelElementEndpointReference traceModelElemEndpointRef : traceMappingRef.getModelElemEndpointRefs()) { String impactedModelUri = ((ModelEndpointReference) traceModelElemEndpointRef.getModelElemRef().eContainer()).getTargetUri(); if (origModelUri.equals(impactedModelUri)) { // target in source model continue; } ModelElementReference impactedModelElemRef = traceModelElemEndpointRef.getModelElemRef(); // navigate tgt mergeability List<EObject> impactedUnifiables = impactedUnifyTable.get(impactedModelElemRef.getUri()); for (EObject impactedUnifiable : impactedUnifiables) { String impactedModelElemUri = MIDRegistry.getModelAndModelElementUris(impactedUnifiable, MIDLevel.INSTANCES)[1]; // create or get impacted model element ref ModelElementReference newImpactedModelElemRef = MIDRegistry.getReference(impactedModelElemUri, impactedModelEndpointRef.getModelElemRefs()); if (newImpactedModelElemRef == null) { newImpactedModelElemRef = impactedModelEndpointRef.createModelElementInstanceAndReference(impactedUnifiable, null); } // add impacted model element endpoint to impact link ModelElementEndpointReference newImpactModelElemEndpointRef = rootModelElemTypeEndpoint.createInstanceAndReference(newImpactedModelElemRef, impactMappingRef); newImpactModelElemEndpointRef.getObject().setName(TGT_MODELELEMENDPOINT_NAME); } } } } @Override public Map<String, Model> run( Map<String, Model> inputsByName, Map<String, GenericElement> genericsByName, Map<String, MID> outputMIDsByName) throws Exception { // input BinaryModelRel diffRel = (BinaryModelRel) inputsByName.get(IN_MODELREL1); BinaryModelRel traceRel = (BinaryModelRel) inputsByName.get(IN_MODELREL2); Model impactedModel = traceRel.getTargetModel(); Map<String, List<ModelElementReference>> origUnifyTable = new HashMap<>(); Map<String, List<MAVOModelElementReference>> origTypeTable = new HashMap<>(); Map<String, List<EObject>> impactedUnifyTable = new HashMap<>(); Map<String, List<EObject>> impactedTypeTable = new HashMap<>(); //TODO MMINT[OVERRIDE] be careful when overriding is implemented createOrigVarTables(traceRel.getModelEndpointRefs().get(0), origUnifyTable, origTypeTable); // O(n log n) createImpactedVarTables(traceRel.getModelEndpointRefs().get(1), impactedUnifyTable, impactedTypeTable); // O(n log n) // create output model relationship ModelRel rootModelRelType = MIDTypeHierarchy.getRootModelRelType(); ModelRel newImpactModelRel = rootModelRelType.createBinaryInstanceAndEndpoints( null, diffRel, impactedModel, outputMIDsByName.get(OUT_MODELREL)); newImpactModelRel.setName(OUT_MODELREL); ModelEndpointReference newDiffModelEndpointRef = newImpactModelRel.getModelEndpointRefs().get(0); ModelEndpointReference newImpactedModelEndpointRef = newImpactModelRel.getModelEndpointRefs().get(1); // loop through diff Mapping rootMappingType = MIDTypeHierarchy.getRootMappingType(); for (Mapping diffMapping : diffRel.getMappings()) { ModelElement diffModelElem = diffMapping.getModelElemEndpoints().get(0).getTarget(); // create diff model element ref ModelElementReference newDiffModelElemRef = newDiffModelEndpointRef.createModelElementInstanceAndReference(diffModelElem, diffModelElem.getName()); // create impact link, add diff model element endpoint to it EList<ModelElementReference> targetModelElemRefs = new BasicEList<ModelElementReference>(); targetModelElemRefs.add(newDiffModelElemRef); MappingReference newImpactMappingRef = rootMappingType.createInstanceAndReferenceAndEndpointsAndReferences(false, targetModelElemRefs); newImpactMappingRef.getObject().setName(OUT_MODELREL); ModelElementEndpointReference newDiffModelElemEndpointRef = newImpactMappingRef.getModelElemEndpointRefs().get(0); newDiffModelElemEndpointRef.getObject().setName(SRC_MODELELEMENDPOINT_NAME); // change impact algorithm List<ModelElementReference> origUnifiables = origUnifyTable.get(diffModelElem.getUri()); if (origUnifiables == null) { // not in the trace rel // get the type it would have if it was in the trace rel ModelElement diffModelElemType = MIDConstraintChecker.getAllowedModelElementType(traceRel.getModelEndpointRefs().get(0), diffModelElem.getEMFInstanceObject()); if (diffModelElemType != null) { List<MAVOModelElementReference> origUnifiablesFromSameType = origTypeTable.get(diffModelElemType.getUri()); for (MAVOModelElementReference origUnifiable : origUnifiablesFromSameType) { if (origUnifiable.getObject().isVar()) { addImpactedModelElementReferences(origUnifiable, newImpactedModelEndpointRef, newImpactMappingRef, impactedUnifyTable); } } } } else { for (ModelElementReference origUnifiable : origUnifiables) { addImpactedModelElementReferences(origUnifiable, newImpactedModelEndpointRef, newImpactMappingRef, impactedUnifyTable); } } } // output Map<String, Model> outputsByName = new HashMap<>(); outputsByName.put(OUT_MODELREL, newImpactModelRel); return outputsByName; } }