blob: 89b6ad66caf59765472bd76741f0dd5237a3cc44 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2018 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - Initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.examples.debug.delegate;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.BasicInvocationDelegate;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.evaluation.EvaluationEnvironment;
import org.eclipse.ocl.pivot.evaluation.EvaluationException;
import org.eclipse.ocl.pivot.ids.IdResolver;
import org.eclipse.ocl.pivot.internal.delegate.InvocationBehavior;
import org.eclipse.ocl.pivot.internal.delegate.OCLDelegateDomain;
import org.eclipse.ocl.pivot.internal.delegate.OCLDelegateException;
import org.eclipse.ocl.pivot.internal.messages.PivotMessagesInternal;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.MetamodelManager;
import org.eclipse.ocl.pivot.utilities.OCL;
import org.eclipse.ocl.pivot.utilities.Query;
import org.eclipse.ocl.pivot.utilities.SemanticException;
import org.eclipse.ocl.pivot.utilities.StringUtil;
/**
* An implementation of an operation-invocation delegate for OCL body
* expressions.
*/
public class OCLInvocationDelegate extends BasicInvocationDelegate
{
protected final OCLDelegateDomain delegateDomain;
private Operation operation;
private ExpressionInOCL specification;
/**
* Initializes me with my operation.
*
* @param operation
* the operation that I handle
*/
public OCLInvocationDelegate(@NonNull OCLDelegateDomain delegateDomain, @NonNull EOperation operation) {
super(operation);
this.delegateDomain = delegateDomain;
}
@Override
public Object dynamicInvoke(InternalEObject target, EList<?> arguments) throws InvocationTargetException {
try {
OCL ocl = delegateDomain.getOCL();
MetamodelManager metamodelManager = ocl.getMetamodelManager();
IdResolver idResolver = ocl.getIdResolver();
ExpressionInOCL specification2 = specification;
if (specification2 == null) {
Operation operation2 = operation;
NamedElement namedElement = delegateDomain.getPivot(NamedElement.class, ClassUtil.nonNullEMF(eOperation));
if (namedElement instanceof Operation) {
operation2 = operation = (Operation) namedElement;
specification2 = specification = InvocationBehavior.INSTANCE.getQueryOrThrow(metamodelManager, operation2);
InvocationBehavior.INSTANCE.validate(operation2);
}
else if (namedElement instanceof Constraint) {
Constraint constraint = (Constraint)namedElement;
specification2 = specification = getExpressionInOCL(metamodelManager, constraint);
ValidationBehavior.INSTANCE.validate(constraint);
}
else if (namedElement != null) {
throw new OCLDelegateException(new SemanticException("Unsupported InvocationDelegate for a " + namedElement.eClass().getName())) ;
}
else {
throw new OCLDelegateException(new SemanticException("Unsupported InvocationDelegate for null")) ;
}
}
Query query = ocl.createQuery(specification2);
EvaluationEnvironment env = query.getEvaluationEnvironment(target);
Object object = target;
Object value = idResolver.boxedValueOf(target);
env.add(ClassUtil.nonNullModel(specification2.getOwnedContext()), value);
List<Variable> parms = specification2.getOwnedParameters();
if (!parms.isEmpty()) {
// bind arguments to parameter names
for (int i = 0; i < parms.size(); i++) {
object = arguments.get(i);
value = idResolver.boxedValueOf(object);
env.add(ClassUtil.nonNullModel(parms.get(i)), value);
}
}
Object result = query.evaluateEcore(eOperation.getEType().getInstanceClass(), target);
return result;
}
catch (EvaluationException e) {
throw new OCLDelegateException(new EvaluationException(e, PivotMessagesInternal.EvaluationResultIsInvalid_ERROR_, operation));
}
}
public @NonNull ExpressionInOCL getExpressionInOCL(@NonNull MetamodelManager metamodelManager, @NonNull Constraint constraint) {
ExpressionInOCL query = null;
Type contextType = (Type) constraint.getContext();
if (contextType != null) {
query = ValidationBehavior.INSTANCE.getQueryOrThrow(metamodelManager, constraint);
}
if (query == null) {
String message = StringUtil.bind(PivotMessagesInternal.MissingBodyForInvocationDelegate_ERROR_, constraint.getContext());
throw new OCLDelegateException(new SemanticException(message));
}
return query;
}
public @NonNull Operation getOperation() {
Operation operation2 = operation;
if (operation2 == null) {
NamedElement pivot = delegateDomain.getPivot(NamedElement.class, ClassUtil.nonNullEMF(eOperation));
if (pivot instanceof Operation) {
operation2 = operation = (Operation) pivot;
}
if (operation2 == null) {
throw new OCLDelegateException(new SemanticException("No pivot property for " + eOperation)) ;
}
}
return operation2;
}
@Override
public String toString() {
if (operation != null) {
return "<" + delegateDomain.getURI() + ":invocation> " + operation; //$NON-NLS-1$ //$NON-NLS-2$
}
else {
String name = eOperation.getEContainingClass().getEPackage().getName()
+ "::" + eOperation.getEContainingClass().getName()
+ "." + eOperation.getName();
return "<" + delegateDomain.getURI() + ":invocation> " + name; //$NON-NLS-1$ //$NON-NLS-2$
}
}
}