/**
* 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.ocl.reasoning;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.values.CollectionValue;
import org.eclipse.ocl.pivot.values.OrderedSetValue;
import org.eclipse.ocl.pivot.values.SetValue;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.utilities.OCL;
import org.eclipse.ocl.pivot.utilities.OCLHelper;
import edu.toronto.cs.se.mmint.MMINTException;
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.relationship.ModelEndpointReference;
import edu.toronto.cs.se.mmint.mid.relationship.ModelRel;
public class OCLReasoningEngine implements IReasoningEngine {
protected final static String OCL_MODELENDPOINT_VARIABLE = "$ENDPOINT_";
protected final static char OCL_VARIABLE_SEPARATOR = '.';
protected EObject getConstraintContext(Model model, String oclConstraint, MIDLevel constraintLevel) throws MMINTException {
//TODO MMINT[CONSTRAINT] find language to express more complex contraints on model rels
boolean isInstancesLevel = model.isInstancesLevel();
EObject modelObj = null;
if (model instanceof ModelRel && oclConstraint.startsWith(OCL_MODELENDPOINT_VARIABLE)) {
String modelEndpointConstraintName = oclConstraint.substring(OCL_MODELENDPOINT_VARIABLE.length(), oclConstraint.indexOf(OCL_VARIABLE_SEPARATOR));
for (ModelEndpointReference modelEndpointRef : ((ModelRel) model).getModelEndpointRefs()) {
//TODO MMINT[ENDPOINT] consider overridden endpoints here
String modelEndpointName = (isInstancesLevel && constraintLevel != MIDLevel.INSTANCES) ?
modelEndpointRef.getObject().getMetatype().getName() :
modelEndpointRef.getObject().getName();
if (modelEndpointConstraintName.equals(modelEndpointName)) {
modelObj = (isInstancesLevel) ?
modelEndpointRef.getObject().getTarget().getEMFInstanceRoot() :
modelEndpointRef.getObject().getTarget().getEMFTypeRoot();
break;
}
}
if (modelObj == null) {
throw new MMINTException("Can't find model endpoint " + modelEndpointConstraintName + " used in model relationship constraint");
}
}
else {
modelObj = (isInstancesLevel) ?
model.getEMFInstanceRoot() :
model.getEMFTypeRoot();
}
return modelObj;
}
@Override
public boolean checkModelConstraint(@NonNull Model model, ExtendibleElementConstraint constraint, @NonNull MIDLevel constraintLevel) {
String oclConstraint = constraint.getImplementation();
try {
EObject modelObj = getConstraintContext(model, oclConstraint, constraintLevel);
if (model instanceof ModelRel && oclConstraint.startsWith(OCL_MODELENDPOINT_VARIABLE)) {
oclConstraint = oclConstraint.substring(oclConstraint.indexOf(OCL_VARIABLE_SEPARATOR) + 1, oclConstraint.length());
}
return checkConstraint(modelObj, oclConstraint);
}
catch (MMINTException e) {
MMINTException.print(IStatus.ERROR, "Can't get context for OCL constraint \"" + constraint + "\" applied to model " + model + " , evaluating to false", e);
return false;
}
}
@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;
}
public boolean checkConstraint(EObject modelObj, String oclConstraint) {
OCL ocl = OCL.newInstance();
try {
OCLHelper helper = ocl.createOCLHelper(modelObj.eClass());
ExpressionInOCL expression = helper.createInvariant(oclConstraint);
return ocl.check(modelObj, expression);
}
catch (Exception e) {
MMINTException.print(IStatus.WARNING, "Error in OCL constraint \"" + oclConstraint + "\" applied to model object " + modelObj + ", evaluating to false", e);
return false;
}
finally {
ocl.dispose();
}
}
public Object evaluateQuery(EObject modelObj, String oclConstraint) {
OCL ocl = OCL.newInstance();
try {
OCLHelper helper = ocl.createOCLHelper(modelObj.eClass());
ExpressionInOCL expression = helper.createQuery(oclConstraint);
Object evaluation = ocl.evaluate(modelObj, expression);
if (evaluation instanceof CollectionValue.Accumulator) {
evaluation = ((CollectionValue.Accumulator) evaluation).getElements();
}
if (evaluation instanceof SetValue) {
evaluation = ((SetValue) evaluation).getElements();
}
if (evaluation instanceof OrderedSetValue) {
evaluation = ((OrderedSetValue) evaluation).getElements();
}
return evaluation;
}
catch (Exception e) {
MMINTException.print(IStatus.ERROR, "OCL derivation error: " + oclConstraint, e);
return null;
}
}
}