/*******************************************************************************
* Copyright (c) 2009, 2010 SAP AG and others.
* 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:
* SAP AG - initial API and implementation
******************************************************************************/
package de.hpi.sam.bp2009.solution.oclToMqlMapping.impl;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.EvaluationEnvironment;
import org.eclipse.ocl.EvaluationVisitorImpl;
import org.eclipse.ocl.ecore.CallOperationAction;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.EcoreEnvironment;
import org.eclipse.ocl.ecore.SendSignalAction;
import org.eclipse.ocl.expressions.IteratorExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.OperationCallExp;
import org.eclipse.ocl.expressions.TypeExp;
import org.eclipse.ocl.util.OCLStandardLibraryUtil;
import org.eclipse.ocl.utilities.PredefinedType;
public class MappingEvaluationVisitor extends EvaluationVisitorImpl<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> {
private boolean isNotMapped = false; ;
private Object query2Result;
public MappingEvaluationVisitor(
Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env,
EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> evalEnv,
Map<? extends EClass, ? extends Set<? extends EObject>> extentMap) {
super(env, evalEnv, extentMap);
}
public MappingEvaluationVisitor(MappingEvaluationVisitor mapEvalVisitor){
super(mapEvalVisitor.getEnvironment(), mapEvalVisitor.getEvaluationEnvironment(), mapEvalVisitor.getExtentMap());
}
@Override
public Object visitExpression(OCLExpression<EClassifier> expression) {
try {
if (couldBeMapped()){
return expression.accept(getVisitor());
}else{
return super.visitExpression(expression);
}
}
catch (RuntimeException e) {
isNotMapped = true;
// failure to evaluate results in invalid
return super.visitExpression(expression);
}
// TODO Check if expression has a self variable, if so there must be a context, this should be replaced by allInstances
}
public boolean couldBeMapped() {
return !isNotMapped;
}
@Override
public Object visitOperationCallExp(OperationCallExp<EClassifier, EOperation> oc) {
if(couldBeMapped()){
if(oc.getOperationCode() == PredefinedType.ALL_INSTANCES){
Set<EObject> contextObjects = new HashSet<EObject>();
// TODO clarify how this should work during partial evaluation where VariableExp should be used instead of variable name
Object self = getEvaluationEnvironment().getValueOf(EcoreEnvironment.SELF_VARIABLE_NAME);
if (self != null && self instanceof EObject) {
contextObjects.add((EObject) self);
} else {
throw new RuntimeException("Need a valid context element even for allInstances() because we need to derive a query scope.");
}
OCLExpression<EClassifier> ocSource = oc.getSource();
EClassifier ocType=null;
if (ocSource instanceof TypeExp){
ocType = (EClassifier) ((TypeExp<EClassifier>) ocSource).getReferredType();
}
/*
* the expression must have the form allInstances()->IteratorExp(body)
* otherwise traverse the AST from beginning
*/
if (oc.eContainer()instanceof IteratorExp && oc.eContainer() != null){
IteratorExp<EClassifier, EParameter> itExp = (org.eclipse.ocl.ecore.IteratorExp) oc.eContainer();
OCLExpression<EClassifier> body = itExp.getBody();
query2Result = new Query2().buildMqlQuery(contextObjects, ocType, body, itExp, this);
if (query2Result == null){
//if the query2 fail traverse the AST from beginning
isNotMapped = true;
return visitExpression((org.eclipse.ocl.ecore.OCLExpression)oc.eContainer());}
else
return query2Result;
}else{
// if the expression has another form, traverse the AST from beginning
isNotMapped=true;
return visitExpression((org.eclipse.ocl.ecore.OCLExpression) oc.eContainer());
}
}else{
//if there isn't any allInstances()
isNotMapped=true;
OCLExpression<EClassifier> oclExp = (org.eclipse.ocl.ecore.OCLExpression) oc.eContainer();
return visitExpression(oclExp);
}
}
else{
return super.visitOperationCallExp(oc);
}
}
@Override
public Object visitIteratorExp(IteratorExp<EClassifier, EParameter> itExp) {
if(couldBeMapped()){
switch (OCLStandardLibraryUtil.getOperationCode(itExp.getName())) {
case PredefinedType.EXISTS:
case PredefinedType.FOR_ALL:
case PredefinedType.SELECT:
case PredefinedType.COLLECT:
case PredefinedType.COLLECT_NESTED:
case PredefinedType.ANY:
if (itExp.getSource() instanceof OperationCallExp)
return visitOperationCallExp((org.eclipse.ocl.ecore.OperationCallExp) itExp.getSource());
else
return super.visitIteratorExp(itExp);
default:
return super.visitIteratorExp(itExp);
}
}
else{
return super.visitIteratorExp(itExp);
}
}
}