/**
* 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.slice;
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.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import edu.toronto.cs.se.mmint.MMINTException;
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.utils.FileUtils;
import edu.toronto.cs.se.mmint.mid.utils.MIDOperatorIOUtils;
public class ModelSlice extends OperatorImpl {
// input-output
private final static @NonNull String IN_MODEL = "model";
private final static @NonNull String OUT_MODEL = "slice";
private static final @NonNull String PROPERTY_IN_IDATTRIBUTE = "idAttribute";
private static final @NonNull String PROPERTY_IN_SLICEIDS = "sliceIds";
private static final @NonNull String PROPERTY_IN_BOUNDARIESIDS_SUFFIX = ".boundariesIds";
// constants
private static final @NonNull String SLICE_MODEL_SUFFIX = "_slice";
private String idAttribute;
private Set<String> sliceIds;
private Map<String, Set<String>> boundariesIds;
private Set<EObject> sliceModelObjs;
@Override
public void readInputProperties(Properties inputProperties) throws MMINTException {
super.readInputProperties(inputProperties);
idAttribute = MIDOperatorIOUtils.getStringProperty(inputProperties, PROPERTY_IN_IDATTRIBUTE);
sliceIds = MIDOperatorIOUtils.getStringPropertySet(inputProperties, PROPERTY_IN_SLICEIDS);
boundariesIds = new HashMap<>();
for (String sliceId : sliceIds) {
boundariesIds.put(sliceId, MIDOperatorIOUtils.getStringPropertySet(inputProperties, sliceId + PROPERTY_IN_BOUNDARIESIDS_SUFFIX));
}
}
private void init() {
sliceModelObjs = new HashSet<>();
}
private void sliceReachableObjects(String sliceId, EObject sliceModelObj) {
if (sliceModelObjs.contains(sliceModelObj)) {
return;
}
String id = null;
try {
id = (String) FileUtils.getModelObjectFeature(sliceModelObj, idAttribute);
}
catch (MMINTException e) {
// ignore and continue
}
sliceModelObjs.add(sliceModelObj);
if (id != null && boundariesIds.get(sliceId).contains(id)) {
return;
}
sliceModelObj.eAllContents().forEachRemaining(reachableModelObj ->
sliceReachableObjects(sliceId, reachableModelObj)
);
sliceModelObj.eCrossReferences().forEach(reachableModelObj ->
sliceReachableObjects(sliceId, reachableModelObj)
);
}
private EObject slice(EObject rootModelObj) {
// collect slice model objects
EObject sliceRootModelObj = EcoreUtil.copy(rootModelObj);
sliceRootModelObj.eAllContents().forEachRemaining(sliceModelObj -> {
String sliceId = null;
try {
sliceId = (String) FileUtils.getModelObjectFeature(sliceModelObj, idAttribute);
}
catch (Exception e) {
// ignore and continue
}
if (sliceId != null && sliceIds.contains(sliceId)) {
sliceReachableObjects(sliceId, sliceModelObj);
}
});
// slice proper
List<EObject> modelObjsToDelete = new ArrayList<>();
sliceRootModelObj.eAllContents().forEachRemaining(modelObjToDelete -> {
if (!sliceModelObjs.contains(modelObjToDelete)) {
modelObjsToDelete.add(modelObjToDelete);
}
});
modelObjsToDelete.forEach(modelObj -> EcoreUtil.delete(modelObj, true));
return sliceRootModelObj;
}
@Override
public Map<String, Model> run(
Map<String, Model> inputsByName, Map<String, GenericElement> genericsByName,
Map<String, MID> outputMIDsByName) throws Exception {
// input
Model model = inputsByName.get(IN_MODEL);
this.init();
String sliceModelUri = FileUtils.getUniqueUri(FileUtils.addFileNameSuffixInUri(model.getUri(), SLICE_MODEL_SUFFIX), true, false);
EObject sliceRootModelObj = this.slice(model.getEMFInstanceRoot());
FileUtils.writeModelFile(sliceRootModelObj, sliceModelUri, true);
Model sliceModel = (isUpdateMID()) ?
model.getMetatype().createInstanceAndEditor(sliceModelUri, outputMIDsByName.get(OUT_MODEL)) :
model.getMetatype().createInstance(sliceModelUri, null);
// output
Map<String, Model> outputsByName = new HashMap<>();
outputsByName.put(OUT_MODEL, sliceModel);
return outputsByName;
}
}