/**
* 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.mmint.operator.merge;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
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.mid.GenericElement;
import edu.toronto.cs.se.mmint.mid.MID;
import edu.toronto.cs.se.mmint.mid.Model;
import edu.toronto.cs.se.mmint.mid.operator.impl.OperatorImpl;
import edu.toronto.cs.se.mmint.mid.relationship.BinaryMapping;
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.relationship.ModelRel;
import edu.toronto.cs.se.mmint.mid.utils.MIDRegistry;
public class ModelRelMerge extends OperatorImpl {
public static class InputConstraint implements IJavaOperatorInputConstraint {
@Override
public boolean isAllowedInput(Map<String, Model> inputsByName) {
ModelRel modelRel1 = (ModelRel) inputsByName.get(IN_MODELREL1);
ModelRel modelRel2 = (ModelRel) inputsByName.get(IN_MODELREL2);
if (modelRel1.getModelEndpoints().size() != 2 || modelRel2.getModelEndpoints().size() != 2) {
return false;
}
Model model11 = modelRel1.getModelEndpoints().get(0).getTarget();
Model model12 = modelRel1.getModelEndpoints().get(1).getTarget();
Model model21 = modelRel2.getModelEndpoints().get(0).getTarget();
Model model22 = modelRel2.getModelEndpoints().get(1).getTarget();
if (model11 == model21 && model12 == model22) {
return true;
}
else if (model11 == model22 && model12 == model21) {
return true;
}
return false;
}
}
// input-output
private final static @NonNull String IN_MODELREL1 = "rel1";
private final static @NonNull String IN_MODELREL2 = "rel2";
private final static @NonNull String OUT_MODELREL = "merge";
// constants
private final static @NonNull String MERGE_SEPARATOR = "+";
private void populate(ModelRel mergedModelRel, ModelRel origModelRel, MID instanceMID) throws MMINTException {
// models
Map<String, ModelElementReference> newModelElemRefs = new HashMap<String, ModelElementReference>();
for (ModelEndpointReference origModelEndpointRef : origModelRel.getModelEndpointRefs()) {
List<ModelEndpointReference> newModelEndpointRefs = MIDRegistry.getEndpointReferences(origModelEndpointRef.getTargetUri(), mergedModelRel.getModelEndpointRefs());
ModelEndpointReference newModelEndpointRef;
if (newModelEndpointRefs.isEmpty()) {
Model newModel = instanceMID.getExtendibleElement(origModelEndpointRef.getTargetUri());
newModelEndpointRef = origModelEndpointRef.getObject().getMetatype().createInstance(newModel, mergedModelRel);
}
else {
newModelEndpointRef = newModelEndpointRefs.get(0);
}
// model elements
for (ModelElementReference origModelElemRef : origModelEndpointRef.getModelElemRefs()) {
ModelElementReference newModelElemRef = MIDRegistry.getReference(origModelElemRef, newModelEndpointRef.getModelElemRefs());
if (newModelElemRef == null) {
EObject newModelObj = origModelElemRef.getObject().getEMFInstanceObject();
newModelElemRef = newModelEndpointRef.createModelElementInstanceAndReference(newModelObj, origModelElemRef.getObject().getName());
newModelElemRefs.put(newModelElemRef.getUri(), newModelElemRef);
}
}
}
// links
for (MappingReference origMappingRef : origModelRel.getMappingRefs()) {
if (mergedModelRel.getMappingRefs().stream()
.anyMatch(mappingRef -> mappingRef.getModelElemEndpointRefs().stream()
.map(ModelElementEndpointReference::getTargetUri)
.collect(Collectors.toSet())
.containsAll(origMappingRef.getModelElemEndpointRefs().stream()
.map(ModelElementEndpointReference::getTargetUri)
.collect(Collectors.toSet())))) {
continue;
}
MappingReference newMappingRef = origMappingRef.getObject().getMetatype().createInstanceAndReference((origMappingRef.getObject() instanceof BinaryMapping), mergedModelRel);
newMappingRef.getObject().setName(origMappingRef.getObject().getName());
for (ModelElementEndpointReference origModelElemEndpointRef : origMappingRef.getModelElemEndpointRefs()) {
ModelElementReference newModelElemRef = newModelElemRefs.get(origModelElemEndpointRef.getTargetUri());
origModelElemEndpointRef.getObject().getMetatype().createInstanceAndReference(newModelElemRef, newMappingRef);
}
}
}
private @NonNull ModelRel merge(@NonNull ModelRel modelRel1, @NonNull ModelRel modelRel2,
@NonNull Model model1, @NonNull Model model2, @NonNull MID instanceMID)
throws MMINTException {
ModelRel mergedRel = MIDTypeHierarchy.getRootModelRelType().createBinaryInstanceAndEndpoints(
null,
model1,
model2,
instanceMID);
mergedRel.setName(modelRel1.getName() + MERGE_SEPARATOR + modelRel2.getName());
populate(mergedRel, modelRel1, instanceMID);
populate(mergedRel, modelRel2, instanceMID);
return mergedRel;
}
@Override
public Map<String, Model> run(Map<String, Model> inputsByName,
java.util.Map<String, GenericElement> genericsByName, Map<String, MID> outputMIDsByName)
throws Exception {
// input
ModelRel modelRel1 = (ModelRel) inputsByName.get(IN_MODELREL1);
ModelRel modelRel2 = (ModelRel) inputsByName.get(IN_MODELREL2);
Model model11 = modelRel1.getModelEndpoints().get(0).getTarget();
Model model12 = modelRel1.getModelEndpoints().get(1).getTarget();
Model model21 = modelRel2.getModelEndpoints().get(0).getTarget();
Model model22 = modelRel2.getModelEndpoints().get(1).getTarget();
Model model1 = null, model2 = null;
if (model11 == model21 && model12 == model22) {
model1 = model11;
model2 = model22;
}
else { // model11 == model22 && model12 == model21
model1 = model11;
model2 = model21;
}
// merge the two model rels
ModelRel mergedRel = merge(modelRel1, modelRel2, model1, model2, outputMIDsByName.get(OUT_MODELREL));
// output
Map<String, Model> outputsByName = new HashMap<>();
outputsByName.put(OUT_MODELREL, mergedRel);
return outputsByName;
}
}