blob: a2c16e6940077ddcede9a7b7bfaca8d39d0913e1 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2002, 2008 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
*
* </copyright>
*
* $Id: OCLHelperImpl.java,v 1.6 2008/04/17 19:38:15 cdamus Exp $
*/
package org.eclipse.ocl.internal.helper;
import java.util.List;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.EnvironmentFactory;
import org.eclipse.ocl.OCL;
import org.eclipse.ocl.ParserException;
import org.eclipse.ocl.expressions.BooleanLiteralExp;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.expressions.UnspecifiedValueExp;
import org.eclipse.ocl.helper.Choice;
import org.eclipse.ocl.helper.ConstraintKind;
import org.eclipse.ocl.helper.OCLHelper;
import org.eclipse.ocl.internal.OCLPlugin;
import org.eclipse.ocl.options.ParsingOptions;
import org.eclipse.ocl.types.OCLStandardLibrary;
import org.eclipse.ocl.utilities.ExpressionInOCL;
import org.eclipse.ocl.utilities.OCLFactory;
import org.eclipse.ocl.utilities.UMLReflection;
/**
* Default implementation of the {@link OCLHelper} interface.
*
* @author Yasser Lulu
* @author Christian W. Damus (cdamus)
*/
class OCLHelperImpl<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>
implements OCLHelper<C, O, P, CT> {
private final EnvironmentFactory<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>
environmentFactory;
private final UMLReflection<PK, C, O, P, EL, PM, S, COA, SSA, CT> uml;
private final OCLFactory oclFactory;
private Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> env;
private OCLSyntaxHelper<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> syntaxHelper;
private boolean validating = true;
private final OCL<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> ocl;
private Diagnostic problems;
/**
* Initializes me with my environment.
*
* @param ocl the OCL environment
*/
OCLHelperImpl(OCL<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> ocl) {
this.ocl = ocl;
uml = ocl.getEnvironment().getUMLReflection();
oclFactory = ocl.getEnvironment().getOCLFactory();
environmentFactory = ocl.getEnvironment().getFactory();
}
public Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>
getEnvironment() {
return env == null? ocl.getEnvironment() : env;
}
public OCL<?, C, O, P, ?, ?, ?, ?, ?, CT, ?, ?> getOCL() {
return ocl;
}
public boolean isValidating() {
return validating;
}
public void setValidating(boolean validating) {
this.validating = validating;
}
/**
* Strips any leading, trailing, or embedded comments from the specified OCL
* expression text.
*
* @param txt an OCL expression
* @return the same, but without any comments. Note that the result
* may be an empty String if <code>txt</code> has only comments
*/
private String removeOCLComments(String txt) {
try {
return HelperUtil.getLogicalLine(txt);
} catch (Exception ex) {
HelperUtil.catchException(ex, getClass(), "removeOCLComments");//$NON-NLS-1$
}
return HelperUtil.EMPTY;
}
private void setEnvironment(Environment<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> env) {
this.env = env;
// forget the cached syntax helper, as its environment is now obsolete
syntaxHelper = null;
}
public void setContext(C context) {
setEnvironment(environmentFactory.createClassifierContext(
ocl.getEnvironment(), context));
}
public void setOperationContext(C context, O operation) {
setContext(context);
setEnvironment(environmentFactory.createOperationContext(env, operation));
}
public void setAttributeContext(C context, P property) {
setContext(context);
setEnvironment(environmentFactory.createAttributeContext(env, property));
}
public void setInstanceContext(Object instance) {
setEnvironment(environmentFactory.createInstanceContext(
ocl.getEnvironment(), instance));
}
public void setInstanceOperationContext(Object instance, O operation) {
setInstanceContext(instance);
setEnvironment(environmentFactory.createOperationContext(env, operation));
}
public void setInstanceAttributeContext(Object instance, P property) {
setInstanceContext(instance);
setEnvironment(environmentFactory.createAttributeContext(env, property));
}
public C getContextClassifier() {
return env.getContextClassifier();
}
public O getContextOperation() {
return env.getContextOperation();
}
public P getContextAttribute() {
return env.getContextProperty();
}
public List<Choice> getSyntaxHelp(ConstraintKind constraintType, String txt) {
if (constraintType == null) {
// query expressions cannot use post-condition constructs such
// as @pre or oclIsNew(), so pretend an invariant constraint
constraintType = ConstraintKind.INVARIANT;
}
return createSyntaxHelper().getSyntaxHelp(constraintType, txt);
}
public OCLExpression<C>
createQuery(String expression) throws ParserException {
if (removeOCLComments(expression).length() > 0) {
// be sure to pass the original expression along to get the right
// position information when parse fails
try {
return HelperUtil.parseQuery(
this, expression, validating, ocl.isParseTracingEnabled());
} catch (RuntimeException e) {
propagate(e, "createQuery"); //$NON-NLS-1$
}
}
// may as well create a boolean-valued expression if none was supplied
return uml.getSpecification(
createNullCondition(
env.getOCLStandardLibrary().getBoolean())).getBodyExpression();
}
public CT createConstraint(ConstraintKind kind, String expression)
throws ParserException {
switch (kind) {
case PRECONDITION:
return createPrecondition(expression);
case BODYCONDITION:
return createBodyCondition(expression);
case POSTCONDITION:
return createPostcondition(expression);
case INITIAL:
return createInitialValueExpression(expression);
case DERIVATION:
return createDerivedValueExpression(expression);
case DEFINITION:
return HelperUtil.parseDefExpression(
this, expression, validating, ocl.isParseTracingEnabled());
default:
return createInvariant(expression);
}
}
public CT createInvariant(String expression) throws ParserException {
if (removeOCLComments(expression).length() > 0) {
// be sure to pass the original expression along to get the right
// position information when parse fails
try {
return HelperUtil.parseInvariant(
this, expression, validating, ocl.isParseTracingEnabled());
} catch (RuntimeException e) {
propagate(e, "createInvariant"); //$NON-NLS-1$
}
}
return createNullCondition(env.getOCLStandardLibrary().getBoolean());
}
public CT createPrecondition(String expression) throws ParserException {
if (removeOCLComments(expression).length() > 0) {
// be sure to pass the original expression along to get the right
// position information when parse fails
try {
return HelperUtil.parsePrecondition(
this, expression, validating, ocl.isParseTracingEnabled());
} catch (RuntimeException e) {
propagate(e, "createPrecondition"); //$NON-NLS-1$
}
}
return createNullCondition(env.getOCLStandardLibrary().getBoolean());
}
public CT createPostcondition(String expression) throws ParserException {
if (removeOCLComments(expression).length() > 0) {
// be sure to pass the original expression along to get the right
// position information when parse fails
try {
return HelperUtil.parsePostcondition(
this, expression, validating, ocl.isParseTracingEnabled());
} catch (RuntimeException e) {
propagate(e, "createPostcondition"); //$NON-NLS-1$
}
}
return createNullCondition(env.getOCLStandardLibrary().getBoolean());
}
public CT createBodyCondition(String expression) throws ParserException {
if (removeOCLComments(expression).length() > 0) {
// be sure to pass the original expression along to get the right
// position information when parse fails
try {
return HelperUtil.parseBodyCondition(
this, expression, validating, ocl.isParseTracingEnabled());
} catch (RuntimeException e) {
propagate(e, "createBodyCondition"); //$NON-NLS-1$
}
}
return createNullCondition(env.getOCLStandardLibrary().getOclVoid());
}
public CT createInitialValueExpression(String expression) throws ParserException {
if (removeOCLComments(expression).length() > 0) {
// be sure to pass the original expression along to get the right
// position information when parse fails
try {
return HelperUtil.parseInitialValueExpression(
this, expression, validating, ocl.isParseTracingEnabled());
} catch (RuntimeException e) {
propagate(e, "createInitialValueExpression"); //$NON-NLS-1$
}
}
return createNullCondition(env.getOCLStandardLibrary().getOclVoid());
}
public CT createDerivedValueExpression(String expression) throws ParserException {
if (removeOCLComments(expression).length() > 0) {
// be sure to pass the original expression along to get the right
// position information when parse fails
try {
return HelperUtil.parseDerivedValueExpression(
this, expression, validating, ocl.isParseTracingEnabled());
} catch (RuntimeException e) {
propagate(e, "createDerivedValueExpression"); //$NON-NLS-1$
}
}
return createNullCondition(env.getOCLStandardLibrary().getOclVoid());
}
@SuppressWarnings("unchecked")
public O defineOperation(String defExpression) throws ParserException {
try {
EObject operation = define(defExpression);
if (!uml.isOperation(operation)) {
// assert that the correct type of feature was defined
throw new ClassCastException();
}
return (O) operation;
} catch (RuntimeException e) {
propagate(e, "define"); //$NON-NLS-1$
}
return null; // make the compiler happy
}
@SuppressWarnings("unchecked")
public P defineAttribute(String defExpression) throws ParserException {
try {
EObject property = define(defExpression);
if (!uml.isProperty(property)) {
// assert that the correct type of feature was defined
throw new ClassCastException();
}
return (P) property;
} catch (RuntimeException e) {
propagate(e, "define"); //$NON-NLS-1$
}
return null; // make the compiler happy
}
EObject define(String defExpression) throws ParserException {
CT constraint = HelperUtil.parseDefExpression(
this, defExpression, validating, ocl.isParseTracingEnabled());
List<EObject> constrainedElement = uml.getConstrainedElements(constraint);
EObject result = constrainedElement.get(1);
if (!ParsingOptions.getValue(getEnvironment(), ParsingOptions.DEFINITION_CONSTRAINS_FEATURE)) {
// remove it for good measure
constrainedElement.remove(result);
}
return result;
}
/**
* Creates a null condition of the specified <code>type</code>.
*
* @param type the condition type
*
* @return an expression whose value is <code>false</code> for boolean type
* or <code>null</code> for anything else
*/
private CT createNullCondition(C type) {
OCLExpression<C> condition;
OCLStandardLibrary<C> stdlib = env.getOCLStandardLibrary();
if (type == stdlib.getBoolean()) {
BooleanLiteralExp<C> literal =
oclFactory.createBooleanLiteralExp();
condition = literal;
uml.setType(literal, env.getOCLStandardLibrary().getBoolean());
literal.setBooleanSymbol(Boolean.FALSE);
} else {
UnspecifiedValueExp<C> unspec =
oclFactory.createUnspecifiedValueExp();
condition = unspec;
if (type == null) {
type = env.getOCLStandardLibrary().getOclVoid();
}
uml.setType(unspec, type);
}
CT result = uml.createConstraint();
ExpressionInOCL<C, PM> spec = uml.createExpressionInOCL();
spec.setBodyExpression(condition);
spec.setContextVariable(env.getSelfVariable());
uml.setSpecification(result, spec);
return result;
}
/**
* Propagates the specified exception as a parsing exception, with
* the requisite tracing.
*
* @param e the exception to propagate
* @param method the name of the method that caught the exception
*
* @throws the exception wrapped in an {@link ParserException}
*/
private void propagate(Exception e, String method) throws ParserException {
OCLPlugin.catching(getClass(), method, e);
ParserException ope = new ParserException(e.getLocalizedMessage(), e);
OCLPlugin.throwing(getClass(), method, ope);
throw ope;
}
/**
* returns the ocl syntax helper object
*
* @return OCLSyntaxHelper
*/
protected OCLSyntaxHelper<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>
createSyntaxHelper() {
if (syntaxHelper == null) {
syntaxHelper = new OCLSyntaxHelper<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E>(
getEnvironment());
}
return syntaxHelper;
}
public Diagnostic getProblems() {
return problems;
}
void setProblems(Diagnostic problems) {
this.problems = problems;
}
}