/**
* 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.propagate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import edu.toronto.cs.se.mavo.MAVOElement;
import edu.toronto.cs.se.mmint.MMINT;
import edu.toronto.cs.se.mmint.MMINTException;
import edu.toronto.cs.se.mmint.java.reasoning.IJavaOperatorInputConstraint;
import edu.toronto.cs.se.mmint.mavo.library.MAVOUtils;
import edu.toronto.cs.se.mmint.mavo.mavomid.BinaryMAVOMapping;
import edu.toronto.cs.se.mmint.mavo.mavomid.BinaryMAVOMappingReference;
import edu.toronto.cs.se.mmint.mavo.mavomid.BinaryMAVOModelRel;
import edu.toronto.cs.se.mmint.mavo.mavomid.MAVOMapping;
import edu.toronto.cs.se.mmint.mavo.mavomid.MAVOModel;
import edu.toronto.cs.se.mmint.mavo.mavomid.MAVOModelElement;
import edu.toronto.cs.se.mmint.mavo.mavomid.MAVOModelElementReference;
import edu.toronto.cs.se.mmint.mavo.mavomid.MAVOModelEndpoint;
import edu.toronto.cs.se.mmint.mid.ExtendibleElement;
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.BinaryMappingReference;
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.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.utils.FileUtils;
import edu.toronto.cs.se.mmint.mid.utils.MIDRegistry;
public class ChangePropagation extends OperatorImpl {
public static class InputConstraint implements IJavaOperatorInputConstraint {
@Override
public boolean isAllowedInput(Map<String, Model> inputsByName) {
//TODO MMINT[OPERATOR] Check that refinement and trace share a model, and that all models involved are mavo models
return true;
}
}
// input-output
private final static @NonNull String IN_MODELREL1 = "refinement";
private final static @NonNull String IN_MODELREL2 = "trace";
private final static @NonNull String OUT_MODEL = "propagated";
private final static @NonNull String OUT_MODELREL1 = "propagatedRefinement";
private final static @NonNull String OUT_MODELREL2 = "propagatedTrace";
// constants
private final static String PROP_MODEL_SUFFIX = "_propagated";
private final static String PROPTRACE_RULE4_LINK_NAME = "rule4Trace";
private final static String NAME_FEATURE = "name";
/**
* Removes a model element and the reference to it from the Instance MID
* that contains them.
*
* @param modelElemRef
* The reference to be removed to the model element to be
* removed.
*/
private void removeModelElementAndModelElementReference(ModelElementReference modelElemRef) throws MMINTException {
//TODO MMINT[OO] does this have a meaning somewhere else?
MID instanceMID = modelElemRef.getMIDContainer();
instanceMID.getExtendibleTable().removeKey(modelElemRef.getUri());
modelElemRef.deleteInstanceReference();
ModelElement modelElem = modelElemRef.getObject();
((Model) modelElem.eContainer()).getModelElems().remove(modelElem);
//TODO MMINT[OO] should remove from all model rels too?
}
private String getModelEObjectUri(String modelElemUri) {
return modelElemUri.substring(0, modelElemUri.indexOf(MMINT.ROLE_SEPARATOR));
}
private ModelElementReference getModelElementReference(String modelElemRefUri, EList<ModelElementReference> modelElemRefs) {
if (modelElemRefUri == null) {
return null;
}
modelElemRefUri = getModelEObjectUri(modelElemRefUri);
for (ModelElementReference modelElemRef : modelElemRefs) {
if (modelElemRefUri.equals(getModelEObjectUri(modelElemRef.getUri()))) {
return modelElemRef;
}
}
return null;
}
private ModelElementReference getModelElementReference(ModelElementReference correspondingModelElemRef, EList<ModelElementReference> modelElemRefs) {
if (correspondingModelElemRef == null) {
return null;
}
return getModelElementReference(correspondingModelElemRef.getUri(), modelElemRefs);
}
private List<BinaryMAVOMappingReference> propagateTraceMappingsFromRefinements(MappingReference refinementMappingRef, BinaryMAVOModelRel traceRel, MAVOModel newPropModel, BinaryMAVOModelRel newPropTraceRel) throws Exception {
ModelEndpointReference origModelEndpointRef_traceRel = traceRel.getModelEndpointRefs().get(0);
String origModelUri = origModelEndpointRef_traceRel.getTargetUri();
// get model element refs in trace rel that got refined
List<ModelElementReference> refinedModelElemRefs_refinementRel = new ArrayList<ModelElementReference>();
List<ModelElementReference> origModelElemRefs_traceRel = new ArrayList<ModelElementReference>();
for (ModelElementEndpointReference refinementModelElemEndpointRef : refinementMappingRef.getModelElemEndpointRefs()) {
ModelElementReference refinementModelElemRef = refinementModelElemEndpointRef.getModelElemRef();
if (((ModelEndpointReference) refinementModelElemRef.eContainer()).getTargetUri().equals(origModelUri)) { // orig model element ref in trace rel
ModelElementReference origModelElemRef_traceRel = getModelElementReference(refinementModelElemRef.getUri(), origModelEndpointRef_traceRel.getModelElemRefs());
if (origModelElemRef_traceRel == null) { // no trace for this model element
continue;
}
origModelElemRefs_traceRel.add(origModelElemRef_traceRel);
}
else { // refined model element ref in refinement rel
refinedModelElemRefs_refinementRel.add(refinementModelElemRef);
}
}
// no propagation or rule 4 propagation
List<BinaryMAVOMappingReference> newPropTraceMappingRefs = new ArrayList<>();
if (origModelElemRefs_traceRel.isEmpty()) {
if (refinementMappingRef.getModelElemEndpointRefs().size() == 1) {
for (ModelElementReference refinedModelElemRef_refinementRel : refinedModelElemRefs_refinementRel) {
BinaryMAVOMappingReference newPropTraceMappingRef = createDanglingTraceMapping(refinedModelElemRef_refinementRel, newPropTraceRel, 0, 1);
if (newPropTraceMappingRef != null) {
newPropTraceMappingRefs.add(newPropTraceMappingRef);
}
}
}
return newPropTraceMappingRefs;
}
// propagate trace links
List<ModelElementReference> newRefinedModelElemRefs_propTraceRel = new ArrayList<ModelElementReference>();
ModelEndpointReference refinedModelEndpointRef_propTraceRel = newPropTraceRel.getModelEndpointRefs().get(0);
for (ModelElementReference refinedModelElemRef_refinementRel : refinedModelElemRefs_refinementRel) {
// create refined model elem ref in propagated trace rel
ModelElementReference newRefinedModelElemRef_propTraceRel = refinedModelEndpointRef_propTraceRel.createModelElementInstanceAndReference(refinedModelElemRef_refinementRel.getObject().getEMFInstanceObject(), refinedModelElemRef_refinementRel.getObject().getName());
newRefinedModelElemRefs_propTraceRel.add(newRefinedModelElemRef_propTraceRel);
}
ModelEndpointReference propModelEndpointRef_propTraceRel = newPropTraceRel.getModelEndpointRefs().get(1);
for (ModelElementReference origModelElemRef_traceRel : origModelElemRefs_traceRel) {
for (ModelElementEndpointReference traceModelElemEndpointRef : origModelElemRef_traceRel.getModelElemEndpointRefs()) {
BinaryMAVOMappingReference traceMappingRef = (BinaryMAVOMappingReference) traceModelElemEndpointRef.eContainer();
BinaryMAVOMapping traceMapping = traceMappingRef.getObject();
ModelElementReference relatedModelElemRef_traceRel = traceMappingRef.getTargetModelElemRef();
String propModelObjUri =
newPropModel.getUri() +
getModelEObjectUri(relatedModelElemRef_traceRel.getUri()).substring(relatedModelElemRef_traceRel.getUri().lastIndexOf(MMINT.MODEL_URI_SEPARATOR));
EObject propModelObj = FileUtils.readModelObject(propModelObjUri, null);
// create propagated model elem ref in propagated trace rel
ModelElementReference newPropModelElemRef_propTraceRel = propModelEndpointRef_propTraceRel.createModelElementInstanceAndReference(propModelObj, relatedModelElemRef_traceRel.getObject().getName());
// create new propagated trace links
for (ModelElementReference newRefinedModelElemRef_propTraceRel : newRefinedModelElemRefs_propTraceRel) {
BinaryMAVOMappingReference newPropTraceMappingRef = (BinaryMAVOMappingReference) traceMapping.getMetatype().createInstanceAndReference(true, newPropTraceRel);
traceMapping.getModelElemEndpoints().get(0).getMetatype().createInstanceAndReference(newRefinedModelElemRef_propTraceRel, newPropTraceMappingRef);
traceMapping.getModelElemEndpoints().get(1).getMetatype().createInstanceAndReference(newPropModelElemRef_propTraceRel, newPropTraceMappingRef);
MAVOMapping newPropTraceMapping = newPropTraceMappingRef.getObject();
newPropTraceMapping.setName(traceMapping.getName());
newPropTraceMapping.setMay(traceMapping.isMay());
newPropTraceMapping.setSet(traceMapping.isSet());
newPropTraceMapping.setVar(traceMapping.isVar());
newPropTraceMappingRefs.add(newPropTraceMappingRef);
}
}
}
return newPropTraceMappingRefs;
}
private BinaryMAVOMappingReference createDanglingTraceMapping(ModelElementReference traceModelElemRefA, BinaryMAVOModelRel traceRel, int indexA, int indexB) throws MMINTException {
// rule 4, 1st half
if (!((MAVOModelEndpoint) traceRel.getModelEndpoints().get(indexB)).getTarget().isInc()) {
return null;
}
ModelElement traceModelElemTypeA = MIDConstraintChecker.getAllowedModelElementType(
traceRel.getModelEndpointRefs().get(indexA),
traceModelElemRefA.getObject().getEMFInstanceObject()
);
if (traceModelElemTypeA == null) {
return null;
}
BinaryMAVOMappingReference newTraceMappingRef = null;
for (MappingReference traceMappingTypeRef : traceRel.getMetatype().getMappingRefs()) {
if (!(traceMappingTypeRef instanceof BinaryMappingReference)) { // a trace rel type is meant to have two model types
continue;
}
ModelElementReference traceModelElemTypeRefA = traceMappingTypeRef.getModelElemEndpointRefs().get(indexA).getModelElemRef();
if (!traceModelElemTypeRefA.getUri().equals(traceModelElemTypeA.getUri())) {
continue;
}
ModelElementEndpointReference traceModelElemTypeEndpointRefB = traceMappingTypeRef.getModelElemEndpointRefs().get(indexB);
if (traceModelElemTypeEndpointRefB.getObject().getLowerBound() < 1) {
continue;
}
// create new dangling trace link
ModelElementReference newTraceModelElemRefA = traceRel.getModelEndpointRefs().get(indexA).createModelElementInstanceAndReference(traceModelElemRefA.getObject().getEMFInstanceObject(), traceModelElemRefA.getObject().getName());
newTraceMappingRef = (BinaryMAVOMappingReference) traceMappingTypeRef.getObject().createInstanceAndReference(true, traceRel);
newTraceMappingRef.getObject().setVar(true);
newTraceMappingRef.getObject().setName(PROPTRACE_RULE4_LINK_NAME);
traceMappingTypeRef.getModelElemEndpointRefs().get(indexA).getObject().createInstanceAndReference(newTraceModelElemRefA, newTraceMappingRef);
// if more than one link type with same model element type A exist, they all get created (the user will merge unnecessary ones)
//TODO MMINT[MAVO] should I also mark them as M, because I want them to be mutually exclusive?
//TODO MMINT[MAVO] (prop rule that forces the removal of M if the endpoints are E sounds wrong in this case, mostly because mutual exclusion has not been formalized)
}
return newTraceMappingRef;
}
private List<BinaryMAVOMappingReference> reduceTraceMappingUncertainty(EObject modelRootB, List<BinaryMAVOMappingReference> propTraceMappingRefs, int indexA, int indexB) throws Exception {
int n = 0;
HashSet<String> uniqueModelElemUrisB = new HashSet<String>();
for (BinaryMappingReference traceMappingRef : propTraceMappingRefs) {
if (traceMappingRef.getModelElemEndpointRefs().size() == 1) { // dangling link
continue;
}
ModelElementReference traceModelElemRefB = traceMappingRef.getModelElemEndpointRefs().get(indexB).getModelElemRef();
if (!uniqueModelElemUrisB.contains(traceModelElemRefB.getUri())) {
n++;
uniqueModelElemUrisB.add(traceModelElemRefB.getUri());
}
}
boolean again = false;
MappingReference unifiedMappingRef = null;
traceLinks:
for (BinaryMAVOMappingReference traceMappingRef : propTraceMappingRefs) {
ModelElementEndpointReference traceModelElemEndpointRefA = traceMappingRef.getModelElemEndpointRefs().get(indexA);
MAVOModelElementReference modelElemRefA = (MAVOModelElementReference) traceModelElemEndpointRefA.getModelElemRef();
MAVOModelElement modelElemA = modelElemRefA.getObject();
// rule 4, 2nd half
if (n == 0) {
completeDanglingTraceMapping(modelRootB, traceMappingRef, modelElemA.getName(), indexB);
again = true;
continue;
}
ModelElementEndpointReference traceModelElemEndpointRefB = traceMappingRef.getModelElemEndpointRefs().get(indexB);
MAVOModelElementReference modelElemRefB = (MAVOModelElementReference) traceModelElemEndpointRefB.getModelElemRef();
MAVOModelElement modelElemB = modelElemRefB.getObject();
BinaryMAVOMapping traceMapping = traceMappingRef.getObject();
boolean Ma = modelElemA.isMay(), Sa = modelElemA.isSet(), Va = modelElemA.isVar();
boolean Mab = traceMapping.isMay(), Sab = traceMapping.isSet(), Vab = traceMapping.isVar();
boolean Mb = modelElemB.isMay(), Sb = modelElemB.isSet(), Vb = modelElemB.isVar();
int Ua = traceModelElemEndpointRefA.getObject().getMetatype().getUpperBound();
int Lb = traceModelElemEndpointRefB.getObject().getMetatype().getLowerBound(), Ub = traceModelElemEndpointRefB.getObject().getMetatype().getUpperBound();
EObject modelObjB = FileUtils.readModelObject(
getModelEObjectUri(modelElemB.getUri()),
modelRootB.eResource()
);
// rule 1
if (Mb && !Mab) {
Mb = false;
modelElemB.setMay(Mb);
MAVOUtils.setMay(modelObjB, Mb);
again = true;
}
// rule 2
if (Sab && !Sa && !Sb) {
Sab = false;
traceMapping.setSet(Sab);
again = true;
}
// rule 3
if (Vab && !Va && !Vb) {
Vab = false;
traceMapping.setVar(Vab);
again = true;
}
if (Lb == 1 && n == 1) {
// rule 5
if (Mab && !Ma) {
Mab = false;
traceMapping.setMay(Mab);
again = true;
}
}
if (Ub == 1) {
if (Ua == -1) {
// rule 6
if (Sb && !Sa && !Mab) {
Sb = false;
modelElemB.setSet(Sb);
MAVOUtils.setSet(modelObjB, Sb);
again = true;
}
}
// rule 7
if (Vab && Vb && !Mab) {
for (BinaryMAVOMappingReference traceMappingRef2 : propTraceMappingRefs) {
if (traceMappingRef2 == traceMappingRef) {
continue;
}
boolean Mac = traceMappingRef2.getObject().isMay();
if (!Mac) {
unifyVarTraceMapping(modelRootB, traceMappingRef, traceMappingRef2, indexA, indexB);
unifiedMappingRef = traceMappingRef;
again = true;
break traceLinks;
}
}
}
}
}
// rule 7
if (unifiedMappingRef != null) {
propTraceMappingRefs.remove(unifiedMappingRef);
unifiedMappingRef = null;
}
// keep reducing uncertainty
if (again) {
reduceTraceMappingUncertainty(modelRootB, propTraceMappingRefs, indexA, indexB);
}
return propTraceMappingRefs;
}
private void unifyModelElementUris(ModelElementReference unifiedModelElemRef, ModelElementReference modelElemRef) {
EMap<String, ExtendibleElement> extendibleTable = modelElemRef.getMIDContainer().getExtendibleTable();
String unifiedModelElemUri = getModelEObjectUri(unifiedModelElemRef.getUri());
String modelElemUri = getModelEObjectUri(modelElemRef.getUri());
ModelEndpointReference modelEndpointRef = (ModelEndpointReference) modelElemRef.eContainer();
String unifiedModelElemUriBase = unifiedModelElemUri.substring(0, unifiedModelElemUri.lastIndexOf('.')+1);
int unifiedModelElemUriIndex = Integer.parseInt(unifiedModelElemUri.substring(unifiedModelElemUri.lastIndexOf('.')+1));
List<ModelElement> otherModelElems = new ArrayList<ModelElement>();
// first pass, modify model element uris
for (ModelElement otherModelElem : modelEndpointRef.getObject().getTarget().getModelElems()) {
String otherModelElemUri = getModelEObjectUri(otherModelElem.getUri());
// other model element to be affected by unification of model elements
if (otherModelElemUri.contains(unifiedModelElemUriBase)) {
String otherModelElemUriExtra = otherModelElemUri.substring(otherModelElemUri.lastIndexOf(unifiedModelElemUriBase) + unifiedModelElemUriBase.length());
int otherModelElemUriIndex = (otherModelElemUriExtra.indexOf(MMINT.URI_SEPARATOR) == -1) ?
Integer.parseInt(otherModelElemUriExtra) :
Integer.parseInt(otherModelElemUriExtra.substring(0, otherModelElemUriExtra.indexOf(MMINT.URI_SEPARATOR)));
String newOtherModelElemUri = null;
if (otherModelElemUriIndex == unifiedModelElemUriIndex) { // uri to be fully replaced
newOtherModelElemUri = otherModelElem.getUri().replace(unifiedModelElemUri, modelElemUri);
}
else if (otherModelElemUriIndex > unifiedModelElemUriIndex) { // uri to be shifted
newOtherModelElemUri = otherModelElem.getUri().replace(unifiedModelElemUriBase + otherModelElemUriIndex, unifiedModelElemUriBase + --otherModelElemUriIndex);
}
if (newOtherModelElemUri != null) {
extendibleTable.removeKey(otherModelElem.getUri());
otherModelElem.setUri(newOtherModelElemUri);
otherModelElems.add(otherModelElem);
}
}
}
// second pass, update extendible table
for (ModelElement otherModelElem : otherModelElems) {
extendibleTable.put(otherModelElem.getUri(), otherModelElem);
}
}
@SuppressWarnings("unchecked")
private void unifyVarTraceMapping(EObject modelRootB, BinaryMappingReference varTraceMappingRef, BinaryMappingReference traceMappingRef, int indexA, int indexB) throws Exception {
ModelElementReference varModelElemRef = varTraceMappingRef.getModelElemEndpointRefs().get(indexB).getModelElemRef();
ModelElementReference modelElemRef = traceMappingRef.getModelElemEndpointRefs().get(indexB).getModelElemRef();
// get var object and other object from same resource
EObject varModelObj = FileUtils.readModelObject(getModelEObjectUri(varModelElemRef.getUri()), modelRootB.eResource());
EObject modelObj = FileUtils.readModelObject(getModelEObjectUri(modelElemRef.getUri()), modelRootB.eResource());
// unify contents
for (EObject varModelObjContent : varModelObj.eContents()) {
EStructuralFeature varModelObjContainingFeature = varModelObjContent.eContainingFeature();
Object value = modelObj.eGet(varModelObjContainingFeature);
if (value instanceof EList) {
((EList<EObject>) value).add(varModelObjContent);
}
}
// remove var object
EcoreUtil.delete(varModelObj);
//TODO MMINT[MISC] should we try to preserve references to it, maybe using EcoreUtil.CrossReferencer?
// remove unified links and model elements
removeModelElementAndModelElementReference(varModelElemRef);
// update uris due to model element unification
unifyModelElementUris(varModelElemRef, modelElemRef);
}
@SuppressWarnings("unchecked")
private EObject[] navigateIncompleteModel(EObject currentContainer, EFactory modelTypeFactory, String modelElemTypeUri, String modelElemName) {
for (EReference containment : currentContainer.eClass().getEAllContainments()) {
EObject currentContainerCopy = EcoreUtil.copy(currentContainer);
EClass containedEClass = (EClass) containment.getEType();
EObject contained = modelTypeFactory.create(containedEClass);
if (contained instanceof MAVOElement) {
((MAVOElement) contained).setVar(true);
}
EStructuralFeature feature = containedEClass.getEStructuralFeature(NAME_FEATURE);
if (feature != null && feature instanceof EAttribute && ((EAttribute) feature).getEType().getName().equals("EString")) {
contained.eSet(feature, modelElemName);
}
Object value = currentContainerCopy.eGet(containment);
if (value instanceof EList) {
((EList<EObject>) value).add(contained);
}
else {
currentContainerCopy.eSet(containment, contained);
}
// model element created
if (modelElemTypeUri.equals(containedEClass.getName())) {
EObject rootContainer = EcoreUtil.getRootContainer(currentContainerCopy);
if (rootContainer == null) {
rootContainer = currentContainerCopy;
}
return new EObject[] {rootContainer, contained};
}
// continue recursion
EObject[] result = navigateIncompleteModel(contained, modelTypeFactory, modelElemTypeUri, modelElemName);
if (result != null) {
return result;
}
}
return null;
}
@SuppressWarnings("unchecked")
private void completeDanglingTraceMapping(EObject modelRootB, MappingReference traceMappingRef, String modelElemName, int indexB) throws Exception {
ModelEndpointReference modelEndpointRef = ((BinaryModelRel) traceMappingRef.eContainer()).getModelEndpointRefs().get(indexB);
Model model = modelEndpointRef.getObject().getTarget();
EFactory modelTypeFactory = model.getMetatype().getEMFTypeRoot().getEFactoryInstance();
ModelElementEndpointReference modelElemTypeEndpointRef = traceMappingRef.getObject().getMetatype().getModelElemEndpointRefs().get(indexB);
ModelElement modelElemType = modelElemTypeEndpointRef.getModelElemRef().getObject();
String modelElemTypeUri = MIDRegistry.getModelAndModelElementUris(modelElemType.getEMFTypeObject(), MIDLevel.TYPES)[1];
EObject[] result = null;
for (EReference containment : modelRootB.eClass().getEAllContainments()) {
EClass containedEClass = (EClass) containment.getEType();
EObject contained = modelTypeFactory.create(containedEClass);
if (contained instanceof MAVOElement) {
((MAVOElement) contained).setVar(true);
}
EStructuralFeature feature = containedEClass.getEStructuralFeature(NAME_FEATURE);
if (feature != null && feature instanceof EAttribute && ((EAttribute) feature).getEType().getName().equals("EString")) {
contained.eSet(feature, modelElemName);
}
result = navigateIncompleteModel(contained, modelTypeFactory, modelElemTypeUri, modelElemName);
if (result != null) {
Object value = modelRootB.eGet(containment);
if (value instanceof EList) {
((EList<EObject>) value).add(result[0]);
}
else {
modelRootB.eSet(containment, result[0]);
}
break;
}
}
ModelElementReference newModelElemRef = modelEndpointRef.createModelElementInstanceAndReference(result[1], null);
modelElemTypeEndpointRef.getObject().createInstanceAndReference(newModelElemRef, traceMappingRef);
}
private void propagateRefinementMappings(BinaryMappingReference propTraceMappingRef, BinaryModelRel refinementRel, Model relatedModel, BinaryModelRel traceRel, BinaryModelRel newPropRefinementRel) throws MMINTException {
ModelElementReference propModelElemRef_propTraceRel = propTraceMappingRef.getTargetModelElemRef();
ModelEndpointReference propModelEndpointRef_propRefinementRel = newPropRefinementRel.getModelEndpointRefs().get(1);
// create new propagated model element refs in propagated refinement rel
boolean duplicateRefinement1 = true;
ModelElementReference newPropModelElemRef = getModelElementReference(propModelElemRef_propTraceRel, propModelEndpointRef_propRefinementRel.getModelElemRefs());
if (newPropModelElemRef == null) {
duplicateRefinement1 = false;
newPropModelElemRef = propModelEndpointRef_propRefinementRel.createModelElementInstanceAndReference(propModelElemRef_propTraceRel.getObject().getEMFInstanceObject(), propModelElemRef_propTraceRel.getObject().getName());
}
ModelElementReference refinedModelElemRef_propTraceRel = propTraceMappingRef.getSourceModelElemRef();
ModelEndpointReference relatedModelEndpointRef_propRefinementRel = newPropRefinementRel.getModelEndpointRefs().get(0);
ModelEndpointReference refinedModelEndpointRef_refinementRel = refinementRel.getModelEndpointRefs().get(1);
String refinedModelUri = refinedModelEndpointRef_refinementRel.getTargetUri();
ModelElementReference refinedModelElemRef_refinementRel = getModelElementReference(refinedModelElemRef_propTraceRel, refinedModelEndpointRef_refinementRel.getModelElemRefs());
ModelElementEndpointReference refinementModelElemEndpointRef = refinedModelElemRef_refinementRel.getModelElemEndpointRefs().get(0); // many to one here has to be mapped through an nary link
MappingReference refinementMappingRef = (MappingReference) refinementModelElemEndpointRef.eContainer();
Mapping refinementMappingType = refinementMappingRef.getObject().getMetatype();
// create new propagated refinement link
MappingReference newPropRefinementMappingRef = refinementMappingType.createInstanceAndReference(false, newPropRefinementRel);
newPropRefinementMappingRef.getObject().setName(refinementMappingRef.getObject().getName());
refinementMappingType.getModelElemEndpoints().get(0).createInstanceAndReference(newPropModelElemRef, newPropRefinementMappingRef);
boolean duplicateRefinement2 = true;
for (ModelElementEndpointReference refinementModelElemEndpointRef2 : refinementMappingRef.getModelElemEndpointRefs()) {
ModelElementReference origModelElemRef_refinementRel = refinementModelElemEndpointRef2.getModelElemRef();
if (((ModelEndpointReference) origModelElemRef_refinementRel.eContainer()).getTargetUri().equals(refinedModelUri)) {
continue;
}
ModelEndpointReference origModelEndpointRef_traceRel = traceRel.getModelEndpointRefs().get(0);
ModelElementReference origModelElemRef_traceRel = getModelElementReference(origModelElemRef_refinementRel, origModelEndpointRef_traceRel.getModelElemRefs());
for (ModelElementEndpointReference traceModelElementEndpoint : origModelElemRef_traceRel.getModelElemEndpointRefs()) {
BinaryMappingReference traceMappingRef = (BinaryMappingReference) traceModelElementEndpoint.eContainer();
ModelElementReference relatedModelElemRef_traceRel = traceMappingRef.getTargetModelElemRef();
// skip uncorrect refinements due to multiple traces for the same orig model element
if (!propModelElemRef_propTraceRel.getObject().getMetatypeUri().equals(relatedModelElemRef_traceRel.getObject().getMetatypeUri())) {
continue;
}
// create new related model element refs in propagated refinement rel
ModelElementReference newRelatedModelElemRef = getModelElementReference(relatedModelElemRef_traceRel, relatedModelEndpointRef_propRefinementRel.getModelElemRefs());
if (newRelatedModelElemRef == null) {
duplicateRefinement2 = false;
newRelatedModelElemRef = relatedModelEndpointRef_propRefinementRel.createModelElementInstanceAndReference(relatedModelElemRef_traceRel.getObject().getEMFInstanceObject(), relatedModelElemRef_traceRel.getObject().getName());
}
refinementMappingType.getModelElemEndpoints().get(0).createInstanceAndReference(newRelatedModelElemRef, newPropRefinementMappingRef);
}
}
// remove duplicate
if (duplicateRefinement1 && duplicateRefinement2) {
newPropRefinementMappingRef.deleteInstanceAndReference();
}
}
@Override
public Map<String, Model> run(
Map<String, Model> inputsByName, Map<String, GenericElement> genericsByName,
Map<String, MID> outputMIDsByName) throws Exception {
BinaryMAVOModelRel refinementRel = (BinaryMAVOModelRel) inputsByName.get(IN_MODELREL1);
MAVOModel origModel = (MAVOModel) refinementRel.getSourceModel();
MAVOModel refinedModel = (MAVOModel) refinementRel.getTargetModel();
BinaryMAVOModelRel traceRel = (BinaryMAVOModelRel) inputsByName.get(IN_MODELREL2);
MAVOModel relatedModel = (MAVOModel) traceRel.getTargetModel();
// create output model and model relationships
MAVOModel newPropModel = (MAVOModel) relatedModel.getMetatype().copyInstanceAndEditor(relatedModel, relatedModel.getName() + PROP_MODEL_SUFFIX, false, outputMIDsByName.get(OUT_MODEL));
BinaryMAVOModelRel newPropRefinementRel = (BinaryMAVOModelRel) refinementRel.getMetatype().createBinaryInstance(null, outputMIDsByName.get(OUT_MODELREL1));
newPropRefinementRel.setName(OUT_MODELREL1);
refinementRel.getModelEndpoints().get(0).getMetatype().createInstance(relatedModel, newPropRefinementRel);
refinementRel.getModelEndpoints().get(1).getMetatype().createInstance(newPropModel, newPropRefinementRel);
BinaryMAVOModelRel newPropTraceRel = (BinaryMAVOModelRel) traceRel.getMetatype().createBinaryInstance(null, outputMIDsByName.get(OUT_MODELREL2));
newPropTraceRel.setName(OUT_MODELREL2);
traceRel.getModelEndpoints().get(0).getMetatype().createInstance(refinedModel, newPropTraceRel);
traceRel.getModelEndpoints().get(1).getMetatype().createInstance(newPropModel, newPropTraceRel);
// change propagation algorithm
List<List<BinaryMAVOMappingReference>> propTraceMappingRefsList = new ArrayList<>();
for (MappingReference refinementMappingRef : refinementRel.getMappingRefs()) {
List<BinaryMAVOMappingReference> propTraceMappingRefs = propagateTraceMappingsFromRefinements(refinementMappingRef, traceRel, newPropModel, newPropTraceRel);
propTraceMappingRefsList.add(propTraceMappingRefs);
}
EObject newPropModelRoot = newPropModel.getEMFInstanceRoot();
for (List<BinaryMAVOMappingReference> propTraceMappingRefs : propTraceMappingRefsList) {
reduceTraceMappingUncertainty(newPropModelRoot, propTraceMappingRefs, 0, 1);
}
FileUtils.writeModelFile(newPropModelRoot, newPropModel.getUri(), true);
for (List<BinaryMAVOMappingReference> propTraceMappingRefs : propTraceMappingRefsList) {
for (BinaryMappingReference propTraceMappingRef : propTraceMappingRefs) {
propagateRefinementMappings(propTraceMappingRef, refinementRel, relatedModel, traceRel, newPropRefinementRel);
}
}
//TODO MMINT[MAVO] reason about how to concretely use indexA and indexB, when the refineUncertainty becomes an independent operator
// output
Map<String, Model> outputsByName = new HashMap<>();
outputsByName.put(OUT_MODEL, newPropModel);
outputsByName.put(OUT_MODELREL1, newPropRefinementRel);
outputsByName.put(OUT_MODELREL2, newPropTraceRel);
return outputsByName;
}
}