Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.eclipse.ocl.AbstractEvaluationVisitor Maven / Gradle / Ivy
/**
*
*
* Copyright (c) 2005, 2009, 2011 IBM Corporation, Zeligsoft Inc., Borland Software Corp., 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
* Zeligsoft - Bugs 238050, 253252
* Radek Dvorak - Bugs 261128, 265066
* Axel Uhl (SAP AG) - Bug 342644
*
*
*
* $Id: AbstractEvaluationVisitor.java,v 1.12 2011/05/01 10:56:50 auhl Exp $
*/
package org.eclipse.ocl;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.internal.OCLPlugin;
import org.eclipse.ocl.internal.OCLStatusCodes;
import org.eclipse.ocl.internal.evaluation.NumberUtil;
import org.eclipse.ocl.internal.l10n.OCLMessages;
import org.eclipse.ocl.options.EvaluationOptions;
import org.eclipse.ocl.types.InvalidType;
import org.eclipse.ocl.types.OCLStandardLibrary;
import org.eclipse.ocl.types.VoidType;
import org.eclipse.ocl.utilities.AbstractVisitor;
import org.eclipse.ocl.utilities.ExpressionInOCL;
import org.eclipse.ocl.utilities.UMLReflection;
import org.eclipse.ocl.utilities.Visitable;
/**
* An evaluation visitor implementation for OCL expressions.
*
* Note that this class is not intended to be used or extended by
* clients. Use the {@link AbstractEvaluationVisitor} interface, instead.
*
*
* See the {@link Environment} class for a description of the
* generic type parameters of this class.
*
*
* @author Tim Klinger (tklinger)
* @author Christian W. Damus (cdamus)
*/
public abstract class AbstractEvaluationVisitor
extends AbstractVisitor
implements EvaluationVisitor {
// stereotypes associated with boolean-valued constraints
private static Set BOOLEAN_CONSTRAINTS;
private EvaluationEnvironment evalEnv;
private Environment env;
private OCLStandardLibrary stdlib;
private Map extends CLS, ? extends Set extends E>> extentMap;
private EvaluationVisitor visitor;
static {
BOOLEAN_CONSTRAINTS = new java.util.HashSet();
BOOLEAN_CONSTRAINTS.add(UMLReflection.INVARIANT);
BOOLEAN_CONSTRAINTS.add(UMLReflection.PRECONDITION);
BOOLEAN_CONSTRAINTS.add(UMLReflection.POSTCONDITION);
}
/**
* Initializes me.
*
* @param env the current environment
* @param evalEnv an evaluation environment (map of variable names to values)
* @param extentMap a map of classes to their instance sets
*/
protected AbstractEvaluationVisitor(
Environment env,
EvaluationEnvironment evalEnv,
Map extends CLS, ? extends Set extends E>> extentMap) {
this.evalEnv = evalEnv;
this.env = env;
stdlib = env.getOCLStandardLibrary();
this.extentMap = extentMap;
this.visitor = this; // assume I have no decorator
}
/**
* Obtains the visitor on which I perform nested
* {@link Visitable#accept(org.eclipse.ocl.utilities.Visitor)} calls. This
* handles the case in which I am decorated by another visitor that must
* intercept every visitXxx() method. If I internally just
* recursively visit myself, then this decorator is cut out of the picture.
*
* @return my delegate visitor, which may be my own self or some other
*/
protected final EvaluationVisitor
getVisitor() {
return visitor;
}
/**
* Sets the evaluation environment to be used by this visitor during
* evaluation.
*
* @param evaluationEnvironment
* non-null evaluation environment
* @throws IllegalArgumentException
* if the passed evaluationEnvironment
is
* null
*
* @since 1.3
*/
protected void setEvaluationEnvironment(
EvaluationEnvironment evaluationEnvironment) {
if (evaluationEnvironment == null) {
throw new IllegalArgumentException("null evaluation environment"); //$NON-NLS-1$
}
this.evalEnv = evaluationEnvironment;
}
/**
* Sets the visitor on which I perform nested
* {@link Visitable#accept(org.eclipse.ocl.utilities.Visitor)} calls.
*
* @param visitor my delegate visitor
*
* @see #getVisitor()
*/
void setVisitor(EvaluationVisitor visitor) {
this.visitor = visitor;
}
// implements the interface method
public EvaluationEnvironment getEvaluationEnvironment() {
return evalEnv;
}
// implements the interface method
public Environment getEnvironment() {
return env;
}
protected UMLReflection getUMLReflection() {
return env.getUMLReflection();
}
// implements the interface method
public Map extends CLS, ? extends Set extends E>> getExtentMap() {
return extentMap;
}
/**
* Obtains my environment's OCL Standard Library implementation.
*
* @return the OCL standard library
*/
protected OCLStandardLibrary getStandardLibrary() {
return stdlib;
}
/**
* Obtains my environment's implementation of the OclInvalid value.
*
* @return the invalid result
* @since 3.0
*/
protected final Object getInvalid() {
return getStandardLibrary().getInvalid();
}
/**
* Obtains my environment's implementation of the OCL Boolean type.
*
* @return the boolean type
*/
protected final C getBoolean() {
return getStandardLibrary().getBoolean();
}
/**
* Obtains my environment's implementation of the OCL String type.
*
* @return the string type
*/
protected final C getString() {
return getStandardLibrary().getString();
}
/**
* Obtains my environment's implementation of the OCL Integer type.
*
* @return the integer type
*/
protected final C getInteger() {
return getStandardLibrary().getInteger();
}
/**
* Obtains my environment's implementation of the OCL UnlimitedNatural type.
*
* @return the unlimited natural type
*/
protected final C getUnlimitedNatural() {
return getStandardLibrary().getUnlimitedNatural();
}
/**
* Obtains my environment's implementation of the OCL Real type.
*
* @return the real type
*/
protected final C getReal() {
return getStandardLibrary().getReal();
}
/**
* Obtains the name of the specified element, if it has one.
*
* @param namedElement a named element
* @return its name, or null
if it has none
*/
protected String getName(Object namedElement) {
return getEnvironment().getUMLReflection().getName(namedElement);
}
/**
* This default implementation simply asks the expression to
* {@linkplain Visitable#accept(org.eclipse.ocl.utilities.Visitor) accept}
* me.
*
* @param expression an OCL expression to evaluate
*
* @return the result of the evaluation
*/
public Object visitExpression(OCLExpression expression) {
try {
return expression.accept(getVisitor());
} catch (EvaluationHaltedException e) {
// evaluation stopped on demand, propagate further
throw e;
} catch (RuntimeException e) {
String msg = e.getLocalizedMessage();
if (msg == null) {
msg = OCLMessages.no_message;
}
OCLPlugin.log(Diagnostic.ERROR, OCLStatusCodes.IGNORED_EXCEPTION_WARNING,
OCLMessages.bind(OCLMessages.EvaluationFailed_ERROR_, msg), e);
// failure to evaluate results in invalid
return getInvalid();
}
}
/**
* This default implementation asserts that the constraint is
* boolean-valued if it is an invariant, pre-condition, or post-condition
* constraint and returns the value of its body expression by delegation to
* {@link #visitExpression(OCLExpression)}.
*/
@Override
public Object visitConstraint(CT constraint) {
OCLExpression body = getSpecification(constraint).getBodyExpression();
boolean isBoolean = BOOLEAN_CONSTRAINTS.contains(
getEnvironment().getUMLReflection().getStereotype(constraint));
if (body == null) {
throw new IllegalArgumentException("constraint has no body expression"); //$NON-NLS-1$
}
if (isBoolean && (body.getType() != getBoolean())) {
throw new IllegalArgumentException("constraint is not boolean"); //$NON-NLS-1$
}
Object result = getVisitor().visitExpression(body);
return isBoolean? Boolean.TRUE.equals(result) : result;
}
// overrides the inherited no-op implementation
@Override
protected ExpressionInOCL getSpecification(CT constraint) {
return getEnvironment().getUMLReflection().getSpecification(constraint);
}
@Override
public String toString() {
StringBuffer result = new StringBuffer(super.toString());
result.append(" (evaluation environment: ");//$NON-NLS-1$
result.append(getEvaluationEnvironment());
result.append(')');
return result.toString();
}
/**
* Convenience method to determine whether the specified value is the null
* or OclInvalid .
*
* @param value a value
*
* @return whether it is undefined
*/
protected boolean isUndefined(Object value) {
return (value == null) ||
(value == getEnvironment().getOCLStandardLibrary().getInvalid());
}
/**
* Invokes the specified additional operation on a target object.
* The invocation is performed in a nested evaluation environment.
*
* @param operation the operation to invoke
* @param body the operation's body expression
* @param target the object on which to evaluate the operation body
* @param args the arguments to the operation call
*/
protected Object call(O operation, OCLExpression body, Object target, Object[] args) {
Environment myEnv =
getEnvironment();
EnvironmentFactory factory =
myEnv.getFactory();
// create a nested evaluation environment for this operation call
EvaluationEnvironment nested =
factory.createEvaluationEnvironment(getEvaluationEnvironment());
// bind "self"
nested.add(Environment.SELF_VARIABLE_NAME, target);
// add the parameter bindings to the local variables
if (args.length > 0) {
int i = 0;
for (PM param : myEnv.getUMLReflection().getParameters(operation)) {
nested.add(myEnv.getUMLReflection().getName(param), args[i++]);
}
}
return factory.createEvaluationVisitor(
myEnv, nested, getExtentMap()).visitExpression(body);
}
/**
* Obtains the body of the specified operation's def or body expression,
* if any.
*
* @param operation an operation
*
* @return its value expression, if any
*/
protected OCLExpression getOperationBody(O operation) {
OCLExpression result = null;
CT body = env.getDefinition(operation);
if (body == null) {
body = env.getBodyCondition(operation);
}
if (body != null) {
result = env.getUMLReflection().getSpecification(body).getBodyExpression();
}
return result;
}
/**
* Obtains the body of the specified property's def or der expression,
* if any.
*
* @param property a property
*
* @return its value expression, if any
*/
protected OCLExpression getPropertyBody(P property) {
OCLExpression result = null;
CT body = env.getDefinition(property);
if (body == null) {
body = env.getDeriveConstraint(property);
}
if (body != null) {
result = env.getUMLReflection().getSpecification(body).getBodyExpression();
}
return result;
}
/**
* Obtains an object's value of the specified additional property.
*
* @param property the property to navigate
* @param derivation the expression that computes its value
* @param target the object in which context to evaluate the derivation
*
* @return the property's value
*/
protected Object navigate(P property, OCLExpression derivation, Object target) {
Environment myEnv =
getEnvironment();
EnvironmentFactory factory =
myEnv.getFactory();
// create a nested evaluation environment for this property call
EvaluationEnvironment nested =
factory.createEvaluationEnvironment(getEvaluationEnvironment());
// bind "self"
nested.add(Environment.SELF_VARIABLE_NAME, target);
return factory.createEvaluationVisitor(
myEnv, nested, getExtentMap()).visitExpression(derivation);
}
/**
* Checks whether the supplied object is an instance of the supplied type.
*
* @param value the value to check
* @param typeArg the type to check
* @return true if the object is an instance of the type, false otherwise.
* An error condition such as a null
typeArg
is
* indicated by a null
return value.
*/
protected Boolean oclIsTypeOf(Object value, Object typeArg) {
@SuppressWarnings("unchecked")
C type = (C) typeArg;
// regardless of the source value, if the type is undefined, then so
// is oclIsTypeOf
if (type == null) {
return null;
}
// the type of null is OclVoid, except that we aren't even allowed to
// ask if not lax-null-handling
if (value == null) {
return isLaxNullHandling()
// VoidType conforms to all other types except OclInvalid
// See Section 8.2 of OCL 2.3 specification (10-11-42)
? Boolean.valueOf(type instanceof VoidType>)
: null;
}
// the type of invalid is OclInvalid, except that we aren't even allowed
// to ask if not lax-null-handling
if (value == stdlib.getInvalid()) {
return isLaxNullHandling()
? Boolean.valueOf(type instanceof InvalidType>)
: null;
}
return Boolean.valueOf(getEvaluationEnvironment().isTypeOf(value, type));
}
/**
* Checks whether the supplied value is an instance of the supplied type or
* one of its super types.
*
* @param value the value to check
* @param typeArg the type to check
* @return true iff the value is of the type or one of its super types.
* An error condition such as a null
typeArg
is
* indicated by a null
return value.
*/
protected Boolean oclIsKindOf(Object value, Object typeArg) {
@SuppressWarnings("unchecked")
C type = (C) typeArg;
// regardless of the source value, if the type is undefined, then so
// is oclIsTypeOf
if (type == null) {
return null;
}
// OclVoid and Invalid conform to all classifiers but their instances
// aren't actually useful as any type but their own. So, in case of lax
// null handling, return TRUE. Otherwise, oclIsKindOf isn't even
// permitted, so return null to generate an OclInvalid down the line
if (value == null) {
return isLaxNullHandling()
? !Boolean.valueOf(type instanceof InvalidType>)
: null;
}
if (value == stdlib.getInvalid()) {
return isLaxNullHandling()
? Boolean.TRUE // OclInvalid conforms to all other types
: null;
}
return Boolean.valueOf(getEvaluationEnvironment().isKindOf(value, type));
}
/**
*
* Tests whether a given number can be safely coerced to Double or
* Integer without changing the value of the number. Safe means
* that coercing a number to Double or Integer and then
* coercing it back to the original type will result in the same value (no
* loss of precision). This is trivial for types, which have a smaller
* domain then Integer or Double , but for
* example a Long number may not be safely coerced to
* Integer .
*
* If the coercion is safe, the number will be returned as either
* Double or Integer , as appropriate to the original
* precision. Otherwise the original number is returned.
*
*
* @param number a number to coerce to Integer or Double
* @return the coerced number, or the original number, if coercion was not safe
*
* @since 1.2
*/
protected Number coerceNumber(Number number) {
return NumberUtil.coerceNumber(number);
}
/**
*
* Coerces the given number to Double or Long precision,
* if possible. Note that this is only impossible for BigDecimal
* or BigInteger values, respectively, that are out of range of
* their primitive counterparts.
*
*
* @param number a number to coerce to Long or Double
* @return the coerced number, or the original number, in case of overflow
*
* @since 1.2
*/
protected Number higherPrecisionNumber(Number number) {
return NumberUtil.higherPrecisionNumber(number);
}
/**
* Queries whether our evaluation environment has the option for
* {@linkplain EvaluationOptions#LAX_NULL_HANDLING lax null handling}
* enabled.
*
* @since 1.3
* @return whether lax null handling is enabled
*/
protected boolean isLaxNullHandling() {
return EvaluationOptions.getValue(getEvaluationEnvironment(),
EvaluationOptions.LAX_NULL_HANDLING);
}
/**
* Evaluates exp
. If the evaluation terminates with an
* exception that does not have special semantics for the OCL evaluator
* itself, such as {@link EvaluationHaltedException}, the exception is
* caught, and {@link #getInvalid() invalid} is returned as the result of
* the evaluation. If the evaluation terminates normally, the evaluation
* result is returned.
*
* Subclasses may override this method to add exceptions to the list of
* exceptions that are not caught because they have special meaning to a
* specialized OCL evaluator.
*
* @since 3.1
*/
protected Object safeVisitExpression(OCLExpression exp) {
Object sourceVal;
try {
sourceVal = exp.accept(getVisitor());
} catch (EvaluationHaltedException ehe) {
throw ehe;
} catch (RuntimeException e) {
sourceVal = getInvalid();
}
return sourceVal;
}
} //EvaluationVisitorImpl