/*******************************************************************************
* Copyright (c) 2012, 2014 Willink Transformations 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:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.pivot.internal.library;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.util.EcoreEList;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.OperationCallExp;
import org.eclipse.ocl.pivot.evaluation.Evaluator;
import org.eclipse.ocl.pivot.evaluation.Executor;
import org.eclipse.ocl.pivot.ids.CollectionTypeId;
import org.eclipse.ocl.pivot.ids.IdResolver;
import org.eclipse.ocl.pivot.ids.TypeId;
import org.eclipse.ocl.pivot.library.AbstractOperation;
import org.eclipse.ocl.pivot.values.InvalidValueException;
/**
* An EInvokeOperation supports evaluation of an operation call by using eInvoke on the underlying eObject.
*/
public class EInvokeOperation extends AbstractOperation
{
protected final @NonNull EOperation eOperation;
public EInvokeOperation(@NonNull EOperation eOperation) {
this.eOperation = eOperation;
EClassifier eType = eOperation.getEType();
if (eType == null) {
throw new IllegalArgumentException("Non-query EOperation");
}
}
/**
* @since 1.1
*/
@Override
public @Nullable Object dispatch(@NonNull Executor executor, @NonNull OperationCallExp callExp, @Nullable Object sourceValue) {
TypeId typeId = callExp.getTypeId();
List<? extends OCLExpression> arguments = callExp.getOwnedArguments();
if (arguments.size() == 0) {
return evaluate(executor, typeId, sourceValue);
}
OCLExpression argument0 = arguments.get(0);
assert argument0 != null;
Object firstArgument = executor.evaluate(argument0);
if (arguments.size() == 1) {
return evaluate(executor, typeId, sourceValue, firstArgument);
}
OCLExpression argument1 = arguments.get(1);
assert argument1 != null;
Object secondArgument = executor.evaluate(argument1);
if (arguments.size() == 2) {
return evaluate(executor, typeId, sourceValue, firstArgument, secondArgument);
}
@Nullable Object[] argumentValues = new @Nullable Object[arguments.size()];
argumentValues[0] = firstArgument;
argumentValues[1] = secondArgument;
for (int i = 2; i < arguments.size(); i++) {
OCLExpression argument = arguments.get(i);
assert argument != null;
argumentValues[i] = executor.evaluate(argument);
}
return evaluate(executor, typeId, sourceValue, argumentValues);
}
/** @deprecated use Executor */
@Deprecated
public @Nullable Object evaluate(@NonNull Evaluator evaluator, @NonNull TypeId returnTypeId, @Nullable Object sourceValue, @Nullable Object @NonNull ... boxedArgumentValues) {
return evaluate(getExecutor(evaluator), returnTypeId, sourceValue, boxedArgumentValues);
}
/**
* @since 1.1
*/
public @Nullable Object evaluate(@NonNull Executor executor, @NonNull TypeId returnTypeId, @Nullable Object sourceValue,
@Nullable Object... boxedArgumentValues) {
EObject eObject = asNavigableObject(sourceValue, eOperation, executor);
// EList<Object> ecoreArguments = executor.getIdResolver().ecoreValuesOfEach(null, boxedArgumentValues);
IdResolver idResolver = executor.getIdResolver();
EList<EParameter> eParameters = eOperation.getEParameters();
Object[] ecoreValues = new Object[boxedArgumentValues.length];
int iMax = Math.min(boxedArgumentValues.length, eParameters.size());
for (int i = 0; i < iMax; i++) {
Object argumentValue = boxedArgumentValues[i];
EParameter eParameter = eParameters.get(i);
ecoreValues[i] = idResolver.ecoreValueOf(eParameter.getEType().getInstanceClass(), argumentValue);
}
EList<Object> ecoreArguments = new EcoreEList.UnmodifiableEList<Object>(null, null, iMax, ecoreValues);
try {
Object eResult = eObject.eInvoke(eOperation, ecoreArguments);
return getResultValue(executor, returnTypeId, eResult);
} catch (InvocationTargetException e) {
return createInvalidValue(e);
}
}
/** @deprecated use Executor */
@Deprecated
protected @Nullable Object getResultValue(@NonNull Evaluator evaluator, @NonNull TypeId returnTypeId, @Nullable Object eResult) {
return evaluate(getExecutor(evaluator), returnTypeId, eResult);
}
/**
* @since 1.1
*/
protected @Nullable Object getResultValue(@NonNull Executor executor, @NonNull TypeId returnTypeId, @Nullable Object eResult) {
if (returnTypeId instanceof CollectionTypeId) {
if (eResult instanceof Iterable<?>) {
return executor.getIdResolver().createCollectionOfAll((CollectionTypeId)returnTypeId, (Iterable<?>)eResult);
}
else {
throw new InvalidValueException("Non-iterable result");
}
} else if (eResult != null) {
@SuppressWarnings("null") @NonNull EClassifier eType = eOperation.getEType();
return executor.getIdResolver().boxedValueOf(eResult, eType);
}
else {
return null;
}
}
}