/*******************************************************************************
* Copyright (c) 2010, 2015 IBM Corporation 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:
* IBM - Initial API and implementation
* Radek Dvorak - Bug 261128
*******************************************************************************/
package org.eclipse.ocl.pivot.internal.helper;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.OCLExpression;
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.evaluation.EvaluationHaltedException;
import org.eclipse.ocl.pivot.evaluation.EvaluationVisitor;
import org.eclipse.ocl.pivot.evaluation.ModelManager;
import org.eclipse.ocl.pivot.ids.IdResolver;
import org.eclipse.ocl.pivot.internal.messages.PivotMessagesInternal;
import org.eclipse.ocl.pivot.internal.utilities.ProblemAware;
import org.eclipse.ocl.pivot.util.PivotPlugin;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.EnvironmentFactory;
import org.eclipse.ocl.pivot.utilities.OCL;
import org.eclipse.ocl.pivot.utilities.Query;
import org.eclipse.ocl.pivot.utilities.ValueUtil;
/**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Query</b></em>'.
* <!-- end-user-doc -->
*/
public class QueryImpl implements Query, ProblemAware
{
private final @NonNull OCL ocl;
private final @NonNull ExpressionInOCL query;
private final @NonNull OCLExpression expression;
private ModelManager modelManager = null;
private EvaluationEnvironment evaluationEnvironment = null;
private Diagnostic evalProblems;
private BasicDiagnostic batchEvalProblems;
public QueryImpl(@NonNull OCL ocl, @NonNull ExpressionInOCL query) {
this.ocl = ocl;
this.query = query;
this.expression = ClassUtil.nonNullState(query.getOwnedBody());
this.modelManager = ocl.getModelManager();
}
@Override
public boolean checkBoxed(@Nullable Object boxedObject) {
if (resultType() != ocl.getStandardLibrary().getBooleanType()) {
IllegalArgumentException error = new IllegalArgumentException(
PivotMessagesInternal.BooleanQuery_ERROR_);
HelperUtil.throwing(getClass(), "check", error);//$NON-NLS-1$
throw error;
}
Object result = evaluateBoxed(boxedObject);
return result == ValueUtil.TRUE_VALUE;
}
@Override
public boolean checkBoxed(@NonNull Iterable<?> boxedObjects) {
if (resultType() != ocl.getStandardLibrary().getBooleanType()) {
IllegalArgumentException error = new IllegalArgumentException(
PivotMessagesInternal.BooleanQuery_ERROR_);
HelperUtil.throwing(getClass(), "check", error);//$NON-NLS-1$
throw error;
}
for (Object boxedObject : boxedObjects) {
Object result = evaluateBoxed(boxedObject);
if (result != ValueUtil.TRUE_VALUE) {
return false;
}
}
return true;
}
@Override
public boolean checkEcore(@Nullable Object ecoreObject) {
if (resultType() != ocl.getStandardLibrary().getBooleanType()) {
IllegalArgumentException error = new IllegalArgumentException(
PivotMessagesInternal.BooleanQuery_ERROR_);
HelperUtil.throwing(getClass(), "check", error);//$NON-NLS-1$
throw error;
}
Object result = evaluateEcore(null, ecoreObject);
return result == ValueUtil.TRUE_VALUE;
}
@Override
public boolean checkEcore(@NonNull Iterable<?> ecoreObjects) {
if (resultType() != ocl.getStandardLibrary().getBooleanType()) {
IllegalArgumentException error = new IllegalArgumentException(
PivotMessagesInternal.BooleanQuery_ERROR_);
HelperUtil.throwing(getClass(), "check", error);//$NON-NLS-1$
throw error;
}
for (Object ecoreObject : ecoreObjects) {
Object result = evaluateEcore(null, ecoreObject);
if (result != ValueUtil.TRUE_VALUE) {
return false;
}
}
return true;
}
/**
* Assigns collected interim diagnostics of batch evaluation to the
* resulting evaluation problems.
*/
private void commitBatchEvaluateProblems() {
evalProblems = batchEvalProblems;
batchEvalProblems = null;
}
@Override
public @Nullable Object evaluateBoxed(@Nullable Object boxedValue) {
// lazily create the evaluation environment, if not already done by
// the client. Initialize it with the "self" context variable
EvaluationEnvironment myEnv = getEvaluationEnvironment(ocl.getEnvironmentFactory().getIdResolver().unboxedValueOf(boxedValue));
Variable contextVariable = ClassUtil.nonNullState(query.getOwnedContext());
myEnv.add(contextVariable, boxedValue);
// Variable resultVariable = specification.getResultVariable();
// if (resultVariable != null) {
// myEnv.add(resultVariable, null);
// }
EnvironmentFactory environmentFactory = ocl.getEnvironmentFactory();
EvaluationVisitor ev = environmentFactory.createEvaluationVisitor(myEnv);
Object boxedResult;
try {
boxedResult = expression.accept(ev);
} catch (EvaluationHaltedException e) {
evalProblems = e.getDiagnostic();
// result = valueFactory.createInvalidValue(obj, null, evalProblems.toString(), e);
throw e;
// } finally {
// myEnv.remove(specification.getContextVariable());
// if (resultVariable != null) {
// myEnv.add(resultVariable, null);
// }
}
return boxedResult;
}
@Override
public @NonNull List<?> evaluateBoxed(@NonNull Iterable<?> boxedObjects) {
List<Object> boxedResults = new ArrayList<Object>();
try {
for (Object boxedObject : boxedObjects) {
boxedResults.add(evaluateBoxed(boxedObject));
handleNextEvaluateProblems();
}
} finally {
commitBatchEvaluateProblems();
}
return boxedResults;
}
@Override
public @Nullable Object evaluateEcore(@Nullable Object ecoreObject) throws EvaluationException {
return evaluateEcore(null, ecoreObject);
}
@Override
public @Nullable Object evaluateEcore(@Nullable Class<?> instanceClass, @Nullable Object ecoreObject) throws EvaluationException {
evalProblems = null;
IdResolver idResolver = ocl.getIdResolver();
Object boxedValue = idResolver.boxedValueOf(ecoreObject);
Object boxedResult = evaluateBoxed(boxedValue);
return idResolver.ecoreValueOf(instanceClass, boxedResult);
}
@Override
public @NonNull EList<?> evaluateEcore(@NonNull Iterable<?> ecoreObjects) throws EvaluationException {
return evaluateEcore(null, ecoreObjects);
}
@Override
public @NonNull EList<?> evaluateEcore(@Nullable Class<?> instanceClass, @NonNull Iterable<?> ecoreObjects) {
EList<Object> ecoreResults = new BasicEList<Object>();
try {
for (Object ecoreObject : ecoreObjects) {
ecoreResults.add(evaluateEcore(instanceClass, ecoreObject));
handleNextEvaluateProblems();
}
} finally {
commitBatchEvaluateProblems();
}
return ecoreResults;
}
@Override
public @Nullable Object evaluateUnboxed(@Nullable Object unboxedObject) throws EvaluationException {
evalProblems = null;
IdResolver idResolver = ocl.getIdResolver();
Object boxedValue = idResolver.boxedValueOf(unboxedObject);
Object boxedResult = evaluateBoxed(boxedValue);
return idResolver.unboxedValueOf(boxedResult);
}
@Override
public @NonNull EvaluationEnvironment getEvaluationEnvironment(@Nullable Object unboxedObject) {
EvaluationEnvironment evaluationEnvironment2 = evaluationEnvironment;
if (evaluationEnvironment2 == null) {
ModelManager modelManager2 = modelManager;
if (modelManager2 == null) {
modelManager = modelManager2 = ocl.getEnvironmentFactory().createModelManager(unboxedObject);
}
evaluationEnvironment = evaluationEnvironment2 = ocl.getEnvironmentFactory().createEvaluationEnvironment(query, modelManager2);
}
return evaluationEnvironment2;
}
@Override
public @NonNull OCLExpression getExpression() {
return expression;
}
@Override
public @NonNull OCL getOCL() {
return ocl;
}
@Override
public Diagnostic getProblems() {
return evalProblems;
}
/**
* Handles problems of single evaluation performed on behalf of batch
* evaluate invocation.
*/
private void handleNextEvaluateProblems() {
Diagnostic nextEvalProblems = getProblems();
if (nextEvalProblems != null) {
if (batchEvalProblems == null) {
BasicDiagnostic rootDiagnostic = new BasicDiagnostic(
nextEvalProblems.getSeverity(), PivotPlugin.PLUGIN_ID,
nextEvalProblems.getCode(), nextEvalProblems.getMessage(),
null);
batchEvalProblems = rootDiagnostic;
}
batchEvalProblems.add(nextEvalProblems);
}
}
@Override
public String queryText() {
return expression.toString();
}
@Override
public @NonNull <T> List<T> rejectEcore(@NonNull Iterable<T> ecoreObjects) {
List<T> result = new BasicEList<T>();
try {
for (T ecoreObject : ecoreObjects) {
if (!checkEcore(ecoreObject)) {
result.add(ecoreObject);
}
handleNextEvaluateProblems();
}
} finally {
commitBatchEvaluateProblems();
}
return result;
}
@Override
public Type resultType() {
return expression.getType();
}
@Override
public @NonNull <T> List<T> selectEcore(@NonNull Iterable<T> ecoreObjects) {
List<T> result = new BasicEList<T>();
try {
for (T ecoreObject : ecoreObjects) {
if (checkEcore(ecoreObject)) {
result.add(ecoreObject);
}
handleNextEvaluateProblems();
}
} finally {
commitBatchEvaluateProblems();
}
return result;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append("Query["); //$NON-NLS-1$
result.append(queryText());
result.append(']');
return result.toString();
}
}