/**
* 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.kleisli.reasoning;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.TreeIterator;
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.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import edu.toronto.cs.se.mmint.MMINTException;
import edu.toronto.cs.se.mmint.mid.EMFInfo;
import edu.toronto.cs.se.mmint.mid.ExtendibleElementConstraint;
import edu.toronto.cs.se.mmint.mid.MIDLevel;
import edu.toronto.cs.se.mmint.mid.Model;
import edu.toronto.cs.se.mmint.mid.operator.OperatorConstraint;
import edu.toronto.cs.se.mmint.mid.reasoning.IReasoningEngine;
import edu.toronto.cs.se.mmint.mid.reasoning.MIDConstraintChecker;
import edu.toronto.cs.se.mmint.mid.utils.FileUtils;
import edu.toronto.cs.se.modelepedia.ocl.reasoning.OCLReasoningEngine;
public class KleisliReasoningEngine implements IReasoningEngine {
public static final String KLEISLI_MODELTYPE_URI_SUFFIX = "_Kleisli";
public static final String LANGUAGE_ID = "KLEISLI";
public static final String ROW_SEPARATOR = "\n";
public static final String UNION_KEYWORD = "union";
public static final String UNION_ASSIGNMENT = ":=";
public static final String ORIGIN_KEYWORD = "origin";
public static final String OCL_SELF = "self";
public static final String QUERY_NULL = "NULL";
public static final String QUERY_MAP_VARIABLE = "_";
public static final String QUERY_MAP_VARIABLE_SEPARATOR1 = ".";
public static final String QUERY_MAP_VARIABLE_SEPARATOR2 = "->get(";
public static final String QUERY_MAP_VARIABLE_SEPARATOR3 = ")";
public void evaluateEClassQuery(String kQuery, OCLReasoningEngine oclReasoner, EObject kRootModelObj, EClass kModelElemTypeClass, EFactory kModelTypeFactory, Map<String, Map<EObject, EObject>> queryUnion) {
for (String kQueryRow : kQuery.split(ROW_SEPARATOR)) {
String[] kQueryAssignment = kQueryRow.split(UNION_ASSIGNMENT);
String oclQuery = kQueryAssignment[1].trim();
String unionName = kQueryAssignment[0].substring(kQueryAssignment[0].indexOf(UNION_KEYWORD)+UNION_KEYWORD.length(), kQueryAssignment[0].length()).trim();
Map<EObject, EObject> queryRow = new LinkedHashMap<EObject, EObject>();
queryUnion.put(unionName, queryRow);
Object queryObjs = oclReasoner.evaluateQuery(kRootModelObj, oclQuery);
if (!(queryObjs instanceof Collection<?>)) {
continue;
}
for (Object queryObj : (Collection<?>) queryObjs) {
EObject modelObj = (EObject) queryObj;
EObject kModelObj = kModelTypeFactory.create(kModelElemTypeClass);
for (EStructuralFeature feature : modelObj.eClass().getEAllStructuralFeatures()) { // copy shared non-containment features
EStructuralFeature kFeature = kModelObj.eClass().getEStructuralFeature(feature.getName());
if ((feature instanceof EReference && ((EReference) feature).isContainment()) || kFeature == null) {
continue;
}
kModelObj.eSet(kFeature, modelObj.eGet(feature));
}
queryRow.put(modelObj, kModelObj);
}
}
}
public void evaluateEReferenceQuery(String kQuery, OCLReasoningEngine oclReasoner, EMFInfo kModelElemTypeEInfo, Map<String, Map<EObject, EObject>> queryUnion, Map<String, Map<String, Map<EObject, EObject>>> queryMap) {
//TODO MMINT[KLEISLI] what happens when the source or target of the derived ereference is not derived (it's not in queryMap)
//TODO MMINT[KLEISLI] what happens when ereference is not derived but the target is? (source can't be)
String[] kQueryRows = kQuery.split(ROW_SEPARATOR);
int i = 0;
for (Map<EObject, EObject> queryRow : queryUnion.values()) {
String oclQuery = kQueryRows[i].replace(ORIGIN_KEYWORD, OCL_SELF);
String mapIndex = null, unionIndex = null;
if (oclQuery.equals(QUERY_NULL)) {
continue;
}
if (oclQuery.startsWith(QUERY_MAP_VARIABLE)) {
int s1 = oclQuery.indexOf(QUERY_MAP_VARIABLE_SEPARATOR1);
int s2 = oclQuery.indexOf(QUERY_MAP_VARIABLE_SEPARATOR2, s1 + QUERY_MAP_VARIABLE_SEPARATOR1.length());
int s3 = oclQuery.lastIndexOf(QUERY_MAP_VARIABLE_SEPARATOR3);
mapIndex = oclQuery.substring(0, s1);
unionIndex = oclQuery.substring(s1 + QUERY_MAP_VARIABLE_SEPARATOR1.length(), s2);
oclQuery = oclQuery.substring(s2 + QUERY_MAP_VARIABLE_SEPARATOR2.length(), s3);
}
for (Entry<EObject, EObject> queryRowEntry : queryRow.entrySet()) {
EObject modelObj = queryRowEntry.getKey(), kModelObj = queryRowEntry.getValue();
EObject modelObjReferrer = (EObject) oclReasoner.evaluateQuery(modelObj, oclQuery);
if (mapIndex != null && unionIndex != null) {
modelObjReferrer = queryMap.get(mapIndex).get(unionIndex).get(modelObjReferrer);
}
if (modelObjReferrer == null || !MIDConstraintChecker.instanceofEMFClass(modelObjReferrer, kModelElemTypeEInfo.getClassName())) {
continue;
}
try {
FileUtils.setModelObjectFeature(modelObjReferrer, kModelElemTypeEInfo.getFeatureName(), kModelObj);
}
catch (MMINTException e) {
MMINTException.print(IStatus.WARNING, "Error setting model object feature, skipping it", e);
}
}
i++;
}
}
public void evaluateEAttributeQuery(String kQuery, OCLReasoningEngine oclReasoner, EObject kRootModelObj, EMFInfo kModelElemTypeEInfo) {
//TODO MMINT[KLEISLI] queries for derived attributes should be as complex as the ones for eclasses and ereferences
TreeIterator<EObject> kModelObjIter = kRootModelObj.eAllContents();
while (kModelObjIter.hasNext()) {
EObject kModelObj = kModelObjIter.next();
if (!MIDConstraintChecker.instanceofEMFClass(kModelObj, kModelElemTypeEInfo.getClassName())) {
continue;
}
Object kModelObjAttr = oclReasoner.evaluateQuery(kModelObj, kQuery);
try {
FileUtils.setModelObjectFeature(kModelObj, kModelElemTypeEInfo.getFeatureName(), kModelObjAttr);
}
catch (MMINTException e) {
MMINTException.print(IStatus.WARNING, "Error setting model object feature, skipping it", e);
}
}
}
@Override
public boolean checkModelConstraint(@NonNull Model model, ExtendibleElementConstraint constraint, MIDLevel constraintLevel) {
return true;
}
@Override
public boolean checkOperatorInputConstraint(@NonNull Map<String, Model> inputsByName, @NonNull OperatorConstraint constraint) {
return true;
}
@Override
public boolean checkModelConstraintConsistency(@NonNull Model modelType, String constraint) {
return true;
}
@Override
public @Nullable Model refineModelByConstraint(@NonNull Model model) {
return null;
}
}