/**
* 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.operator.match;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;
import java.util.Set;
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.ModelEndpoint;
import edu.toronto.cs.se.mmint.mid.operator.impl.OperatorImpl;
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.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.FileUtils;
import edu.toronto.cs.se.mmint.mid.utils.MIDOperatorIOUtils;
public class ModelMatch extends OperatorImpl {
public static class InputConstraint implements IJavaOperatorInputConstraint {
@Override
public boolean isAllowedInput(Map<String, Model> inputsByName) {
Model srcModel = inputsByName.get(IN_MODEL1);
Model tgtModel = inputsByName.get(IN_MODEL2);
if (srcModel == tgtModel) {
return false;
}
return true;
}
}
// input-output
private final static @NonNull String IN_MODEL1 = "model1";
private final static @NonNull String IN_MODEL2 = "model2";
private final static @NonNull String OUT_MODELREL = "match";
private final static @NonNull String PROPERTY_IN_MATCHATTRIBUTE = "matchAttribute";
private final static @NonNull String PROPERTY_IN_MATCHATTRIBUTE_DEFAULT = "name";
// constants
private final static @NonNull String MODELREL_NAME = "match";
protected String matchAttribute;
@Override
public boolean isCommutative() {
return true;
}
@Override
public void readInputProperties(Properties inputProperties) throws MMINTException {
matchAttribute = MIDOperatorIOUtils.getOptionalStringProperty(inputProperties, PROPERTY_IN_MATCHATTRIBUTE, PROPERTY_IN_MATCHATTRIBUTE_DEFAULT);
}
private void matchModelObjAttributes(EObject modelObj, ModelEndpointReference modelEndpointRef, Map<String, Set<EObject>> modelObjAttrs, Map<EObject, ModelEndpointReference> modelObjTable) {
Object modelObjAttr;
try {
modelObjAttr = FileUtils.getModelObjectFeature(modelObj, matchAttribute);
if (modelObjAttr != null && modelObjAttr instanceof String) {
Set<EObject> modelObjs = modelObjAttrs.get(modelObjAttr);
if (modelObjs == null) {
modelObjs = new HashSet<>();
modelObjAttrs.put((String) modelObjAttr, modelObjs);
}
modelObjs.add(modelObj);
modelObjTable.put(modelObj, modelEndpointRef);
}
}
catch (MMINTException e) {
// do nothing
}
for (EObject contained : modelObj.eContents()) {
matchModelObjAttributes(contained, modelEndpointRef, modelObjAttrs, modelObjTable);
}
}
protected void createMatchLinks(ModelRel matchRel, Map<String, Set<EObject>> modelObjAttrs, Map<EObject, ModelEndpointReference> modelObjTable) throws MMINTException {
Mapping rootMappingType = MIDTypeHierarchy.getRootMappingType();
ModelElementEndpoint rootModelElemTypeEndpoint = MIDTypeHierarchy.getRootModelElementTypeEndpoint();
for (Entry<String, Set<EObject>> entry : modelObjAttrs.entrySet()) {
Set<EObject> modelObjs = entry.getValue();
if (modelObjs.size() < 2) {
continue;
}
String modelObjAttr = entry.getKey();
// create link
MappingReference matchMappingRef = rootMappingType.createInstanceAndReference((modelObjs.size() == 2), matchRel);
matchMappingRef.getObject().setName(modelObjAttr);
for (EObject modelObj : modelObjs) {
ModelEndpointReference modelEndpointRef = modelObjTable.get(modelObj);
// create model element
ModelElementReference matchModelElemRef = modelEndpointRef.createModelElementInstanceAndReference(modelObj, null);
// create model element endpoints
rootModelElemTypeEndpoint.createInstanceAndReference(matchModelElemRef, matchMappingRef);
}
}
}
private ModelRel match(List<Model> models, MID instanceMID) throws MMINTException {
// create model relationship among models
ModelRel matchRel = (models.size() == 2) ?
MIDTypeHierarchy.getRootModelRelType().createBinaryInstance(null, instanceMID) :
(ModelRel) MIDTypeHierarchy.getRootModelRelType().createInstance(null, instanceMID);
matchRel.setName(MODELREL_NAME);
// loop through selected models
ModelEndpoint rootModelTypeEndpoint = MIDTypeHierarchy.getRootModelTypeEndpoint();
Map<String, Set<EObject>> modelObjAttrs = new HashMap<>();
Map<EObject, ModelEndpointReference> modelObjTable = new HashMap<EObject, ModelEndpointReference>();
for (Model model : models) {
// create model endpoint
ModelEndpointReference newModelEndpointRef = rootModelTypeEndpoint.createInstance(model, matchRel);
// look for identical names in the models
matchModelObjAttributes(model.getEMFInstanceRoot(), newModelEndpointRef, modelObjAttrs, modelObjTable);
}
// create model relationship links
createMatchLinks(matchRel, modelObjAttrs, modelObjTable);
return matchRel;
}
@Override
public Map<String, Model> run(
Map<String, Model> inputsByName, Map<String, GenericElement> genericsByName,
Map<String, MID> outputMIDsByName) throws Exception {
// input
//TODO MMINT[MAP] Reenable when map handles varargs
//List<Model> models = MultiModelOperatorUtils.getVarargs(inputsByName, IN_MODEL1);
List<Model> models = new ArrayList<>();
models.add(inputsByName.get(IN_MODEL1));
models.add(inputsByName.get(IN_MODEL2));
// create match
ModelRel matchRel = match(models, outputMIDsByName.get(OUT_MODELREL));
// output
Map<String, Model> outputsByName = new HashMap<>();
outputsByName.put(OUT_MODELREL, matchRel);
return outputsByName;
}
}