/*
* Copyright (c) 2005, 2008 Borland Software Corporation
*
* 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:
* Radek Dvorak (Borland) - initial API and implementation
*/
package org.eclipse.gmf.internal.validate.expressions;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.ETypedElement;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.gmf.internal.validate.DebugOptions;
import org.eclipse.gmf.internal.validate.GMFValidationPlugin;
import org.eclipse.gmf.internal.validate.LabelProvider;
import org.eclipse.gmf.internal.validate.Messages;
import org.eclipse.gmf.internal.validate.StatusCodes;
import org.eclipse.gmf.internal.validate.Trace;
/**
* This class represents the base for expression. Clients providing new types
* of expression should sublass this class.
*/
public abstract class AbstractExpression implements IModelExpression {
private IStatus status;
private String body;
private EClassifier contextClassifier;
private Map<String, EClassifier> extEnv;
/**
* Constructs expression from its body, with specified context.
*
* @param body
* specifies the evaluation logic in the language recognized by
* this expression.
* @param context
* the class in which context the expression is to be parsed
* @param extendedEnv
* additional parsing context information, can be
* <code>null</code>
* @throws IllegalArgumentException
* if any of the passed <code>body</code>,
* <code>contextClassifier</code> is <code>null</code>
*/
protected AbstractExpression(String body, EClassifier context, IParseEnvironment extendedEnv) {
if(body == null || context == null) {
throw new IllegalArgumentException("null body or context-class"); //$NON-NLS-1$
}
this.body = body;
this.contextClassifier = context;
this.status = Status.OK_STATUS;
if(extendedEnv != null) {
this.extEnv = new HashMap<String, EClassifier>(5);
for (String nextVar : extendedEnv.getVariableNames()) {
extEnv.put(nextVar, extendedEnv.getTypeOf(nextVar));
}
} else {
this.extEnv = Collections.emptyMap();
}
}
protected Map<String, EClassifier> getExtEnvironment() {
return extEnv;
}
public boolean isLooselyTyped() {
return true;
}
protected void setStatus(IStatus status) {
this.status = status;
}
/**
* Performs evaluation of this expression in the context.
* <p>
* This method gets called by {@link #evaluate(Object) } only if this
* expression has <code>OK</code> status and the passed context is valid
*
* @param context
* the context instance for evaluation.
*
* @return result of this expression evalutation. In case this expression
* status is not <code>OK</code> status, <code>null</code> is
* returned.
*/
protected abstract Object doEvaluate(Object context);
/**
* Performs evaluation of this expression in the extended context.
* <p>
* This method gets called by {@link #evaluate(Object) } only if this
* expression has <code>OK</code> status and the passed context is valid
*
* @param context
* the context instance for evaluation.
* @param extendedEnv
* the environment with custom variables intialized for
* evaluation
*
* @return result of this expression evalutation. In case this expression
* status is not <code>OK</code> status, <code>null</code> is
* returned.
*/
protected abstract Object doEvaluate(Object context, IEvaluationEnvironment extendedEnv);
public EClassifier getResultType() {
return EcorePackage.eINSTANCE.getEJavaObject();
}
public abstract boolean isAssignableTo(EClassifier ecoreType);
public abstract boolean isAssignableToElement(ETypedElement typedElement);
public abstract String getLanguage();
public final Object evaluate(Object context) {
return evaluate(context, null);
}
public final Object evaluate(Object contextInstance, IEvaluationEnvironment extendedEnv) {
if(contextInstance == null || !hasCompatibleContext(contextInstance)) {
throw new IllegalArgumentException("Invalid evaluation context:" + contextInstance); //$NON-NLS-1$
}
if(getStatus().isOK()) {
try {
if(extendedEnv != null) {
return doEvaluate(contextInstance, extendedEnv);
}
return doEvaluate(contextInstance);
} catch (RuntimeException e) {
IStatus status = GMFValidationPlugin.createStatus(
IStatus.ERROR, StatusCodes.UNEXPECTED_EVALUATION_ERROR,
Messages.unexpectedExprEvalError, e);
GMFValidationPlugin.log(status);
Trace.catching(DebugOptions.EXCEPTIONS_CATCHING, e);
}
}
return null;
}
public IStatus getStatus() {
return status;
}
public String getBody() {
return body;
}
public EClassifier getContext() {
return contextClassifier;
}
public String toString() {
return body + " in context:[" + LabelProvider.INSTANCE.getObjectLabel(contextClassifier) + "] "; //$NON-NLS-1$ //$NON-NLS-2$
}
private boolean hasCompatibleContext(Object ctxInstance) {
if(contextClassifier instanceof EClass) {
EClass contextClass = (EClass)contextClassifier;
return (ctxInstance instanceof EObject) ?
contextClass.isSuperTypeOf(((EObject)ctxInstance).eClass()) : false;
}
return contextClassifier.isInstance(ctxInstance);
}
}