/*
* Copyright (c) 2014, 2015 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.validation;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EObjectValidator;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.EcoreValidator;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.common.OCLCommon;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.StandardLibrary;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.evaluation.AbstractConstraintEvaluator;
import org.eclipse.ocl.pivot.internal.delegate.InvocationBehavior;
import org.eclipse.ocl.pivot.internal.delegate.SettingBehavior;
import org.eclipse.ocl.pivot.internal.delegate.ValidationBehavior;
import org.eclipse.ocl.pivot.internal.manager.MetamodelManagerInternal;
import org.eclipse.ocl.pivot.internal.messages.PivotMessagesInternal;
import org.eclipse.ocl.pivot.internal.utilities.OCLInternal;
import org.eclipse.ocl.pivot.internal.utilities.PivotConstantsInternal;
import org.eclipse.ocl.pivot.util.PivotPlugin;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.ParserContext;
import org.eclipse.ocl.pivot.utilities.ParserException;
import org.eclipse.ocl.pivot.utilities.StringUtil;
import org.eclipse.ocl.pivot.utilities.TracingOption;
import org.eclipse.ocl.pivot.values.InvalidValueException;
import org.eclipse.ocl.pivot.values.TemplateParameterSubstitutions;
/**
* EcoreOCLEValidator provides the validation support for Ecore elements that exploit OCL.
* <p>
* Typically used with a Diagnostician as:
* <pre>
* EValidatorRegistryImpl registry = new EValidatorRegistryImpl();
* registry.put(EcorePackage.eINSTANCE, EcoreOCLEValidator.INSTANCE);
* Diagnostician diagnostician = new Diagnostician(registry);
* Diagnostic diagnostic = dignostician.validate(eObject, validationContext);
* </pre>
*/
public class EcoreOCLEValidator implements EValidator
{
public static final String UNKNOWN_DETAIL = "Unknown ''{0}'' detail for ''{1}''";
public static final String MISSING_DELEGATE = "Missing ''{0}'' delegate for ''{1}''";
public static final String EXTRA_CONSTRAINTS_ANNOTATION_ENTRY = "Extra ''constraints'' annotation entry for ''{0}'' in ''{1}''";
public static final String MISSING_CONSTRAINTS_ANNOTATION_ENTRY = "Missing ''constraints'' annotation entry for ''{0}'' in ''{1}''";
public static final String MISSING_CONSTRAINTS = "Missing constraints annotation for ''{0}''";
public static final String PARSING_ERROR_2 = "Parsing error ''{0}'' for ''{1}'' ''{2}''";
public static final String PARSING_ERROR_1 = "Parsing error ''{0}'' for ''{1}''";
public static final String INCOMPATIBLE_TYPE_2 = "Incompatible type ''{0}'' for ''{1}'' ''{2}''";
public static final String INCOMPATIBLE_TYPE_1 = "Incompatible type ''{0}'' for ''{1}''";
public static final String NULL_EXPRESSION = "Null expression for ''{0}''";
public static final String NULL_PROPERTY_KEY = "Non-null ''derivation'' or ''initial'' detail allowed for ''{0}''";
public static final String EXTRA_PROPERTY_KEY = "Only ''derivation'' or ''initial'' detail allowed for ''{0}''";
public static final String DOUBLE_PROPERTY_KEY = "Both ''derivation'' and ''initial'' detail for ''{0}''";
public static final String MISSING_PROPERTY_KEY = "Missing ''" + SettingBehavior.DERIVATION_CONSTRAINT_KEY + "'' or ''" + SettingBehavior.INITIAL_CONSTRAINT_KEY + "'' detail for ''{0}''";
/**
* ConstraintEvaluatorWithoutDiagnostics provides the minimal ConstraintEvaluator support for
* use when no diagnostics are required.
*/
public static class ConstraintEvaluatorWithoutDiagnostics extends AbstractConstraintEvaluator<Boolean>
{
public ConstraintEvaluatorWithoutDiagnostics(@NonNull ExpressionInOCL expression) {
super(expression);
}
@Override
protected String getObjectLabel() {
throw new UnsupportedOperationException(); // Cannot happen;
}
@Override
protected Boolean handleExceptionResult(@NonNull Throwable e) {
return Boolean.FALSE;
}
@Override
protected Boolean handleFailureResult(@Nullable Object result) {
return Boolean.FALSE;
}
@Override
protected Boolean handleInvalidExpression(@NonNull String message) {
return Boolean.FALSE;
}
@Override
protected Boolean handleInvalidResult(@NonNull InvalidValueException e) {
return Boolean.FALSE;
}
@Override
protected Boolean handleSuccessResult() {
return Boolean.TRUE;
}
}
/**
* ConstraintEvaluatorWithoutDiagnostics provides the richer ConstraintEvaluator support for
* use when diagnostics are required.
*/
public static class ConstraintEvaluatorWithDiagnostics extends AbstractConstraintEvaluator<Boolean>
{
protected final @NonNull EObject eObject;
protected final @NonNull DiagnosticChain diagnostics;
protected final @NonNull EObject diagnosticEObject;
protected final boolean mayUseNewLines;
public ConstraintEvaluatorWithDiagnostics(@NonNull ExpressionInOCL expression, @NonNull EObject eObject,
@NonNull DiagnosticChain diagnostics, @NonNull EObject diagnosticEObject, boolean mayUseNewLines) {
super(expression);
this.diagnosticEObject = diagnosticEObject;
this.eObject = eObject;
this.diagnostics = diagnostics;
this.mayUseNewLines = mayUseNewLines;
}
@Override
protected String getObjectLabel() {
return NameUtil.qualifiedNameFor(eObject);
}
@Override
protected Boolean handleExceptionResult(@NonNull Throwable e) {
String message = StringUtil.bind(PivotMessagesInternal.ValidationResultIsInvalid_ERROR_, getConstraintTypeName(), getConstraintName(), getObjectLabel(), e.toString());
if (!mayUseNewLines) {
message = message.replace("\n", "");
}
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { diagnosticEObject }));
return Boolean.FALSE;
}
@Override
protected Boolean handleFailureResult(@Nullable Object result) {
int severity = getConstraintResultSeverity(result);
String message = getConstraintResultMessage(result);
diagnostics.add(new BasicDiagnostic(severity, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { diagnosticEObject }));
return Boolean.FALSE;
}
@Override
protected Boolean handleInvalidExpression(@NonNull String message) {
String message2 = message;
if (!mayUseNewLines) {
message2 = message.replace("\n", "");
}
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EObjectValidator.DIAGNOSTIC_SOURCE,
0, message2.replace("\n", " - "), new Object [] { diagnosticEObject }));
return Boolean.FALSE;
}
@Override
protected Boolean handleInvalidResult(@NonNull InvalidValueException e) {
String message = StringUtil.bind(PivotMessagesInternal.ValidationResultIsInvalid_ERROR_,
getConstraintTypeName(), getConstraintName(), getObjectLabel(), e.getLocalizedMessage());
if (!mayUseNewLines) {
message = message.replace("\n", "");
}
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { diagnosticEObject }));
return Boolean.FALSE;
}
@Override
protected Boolean handleSuccessResult() {
return Boolean.TRUE;
}
}
/**
* WeakOCLReference maintains the reference to the OCL context within the Diagnostician context and
* disposes of it once the Diagnostician is done.
*/
protected static final class WeakOCLReference extends WeakReference<OCLInternal>
{
protected final @NonNull OCLInternal ocl;
protected WeakOCLReference(@NonNull OCLInternal ocl) {
super(ocl);
this.ocl = ocl;
}
@Override
public void finalize() {
new Thread("OCL-Finalizer")
{
@Override
public void run() {
ocl.dispose();
}
}.start();
}
}
public static final @NonNull EcoreOCLEValidator INSTANCE = new EcoreOCLEValidator(true);
public static final @NonNull EcoreOCLEValidator NO_NEW_LINES = new EcoreOCLEValidator(false);
public static final @NonNull TracingOption VALIDATE_INSTANCE = new TracingOption(PivotPlugin.PLUGIN_ID, "validate/instance");
public static final @NonNull TracingOption VALIDATE_OPAQUE_ELEMENT = new TracingOption(PivotPlugin.PLUGIN_ID, "validate/opaqueElement");
protected static void gatherTypes(@NonNull Set<org.eclipse.ocl.pivot.Class> allTypes, @NonNull Set<Constraint> allConstraints, org.eclipse.ocl.pivot.@NonNull Class newType) {
if (allTypes.add(newType)) {
allConstraints.addAll(newType.getOwnedInvariants());
for (org.eclipse.ocl.pivot.Class superType : newType.getSuperClasses()) {
if (superType != null) {
gatherTypes(allTypes, allConstraints, superType);
}
}
}
}
protected final boolean mayUseNewLines;
public EcoreOCLEValidator(boolean mayUseNewLines) {
this.mayUseNewLines = mayUseNewLines;
}
/**
* Return the OCL context for the validation, caching the created value in the validation context for re-use by
* further validations. The cached reference is weak to ensure that the OCL context is disposed once no longer in use.
*/
protected OCLInternal getOCL(@NonNull Map<Object, Object> context) {
OCLInternal ocl = null;
Object oclRef = context.get(WeakOCLReference.class);
if (oclRef instanceof WeakOCLReference) {
ocl = ((WeakOCLReference)oclRef).get();
}
if (ocl == null) {
ocl = OCLInternal.newInstance();
context.put(WeakOCLReference.class, new WeakOCLReference(ocl));
}
return ocl;
}
protected boolean isOCL(List<String> someDelegates) {
for (String aDelegate : someDelegates) {
if (OCLCommon.isDelegateURI(aDelegate)) {
return true;
}
}
return false;
}
@Override
public boolean validate(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) {
return validate(eObject.eClass(), eObject, diagnostics, context);
// return true;
}
@Override
public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) {
assert context != null;
boolean allOk = true;
if (eObject instanceof EPackage) {
EPackage ePackage = (EPackage)eObject;
allOk = validateEPackage(ePackage, diagnostics, context);
}
else if (eObject instanceof EClassifier) {
EClassifier eClassifier = (EClassifier)eObject;
allOk = validateEClassifier(eClassifier, diagnostics, context);
}
else if (eObject instanceof EOperation) {
EOperation eOperation = (EOperation)eObject;
allOk = validateEOperation(eOperation, diagnostics, context);
}
else if (eObject instanceof EStructuralFeature) {
EStructuralFeature eStructuralFeature = (EStructuralFeature)eObject;
allOk = validateEStructuralFeature(eStructuralFeature, diagnostics, context);
}
return allOk;
}
@Override
public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context) {
return true;
}
protected boolean validateEClassifier(@NonNull EClassifier eClassifier, DiagnosticChain diagnostics, @NonNull Map<Object, Object> context) {
boolean allOk = true;
String constraintsAnnotation = EcoreUtil.getAnnotation(eClassifier, EcorePackage.eNS_URI, "constraints");
EAnnotation eAnnotation = OCLCommon.getDelegateAnnotation(eClassifier);
if (eAnnotation != null) {
OCLInternal ocl = getOCL(context);
MetamodelManagerInternal metamodelManager = ocl.getMetamodelManager();
StandardLibrary standardLibrary = ocl.getStandardLibrary();
EMap<String, String> details = eAnnotation.getDetails();
for (String constraintName : details.keySet()) {
String value = details.get(constraintName);
allOk = validateExpression(metamodelManager, eClassifier, value, standardLibrary.getBooleanType(), constraintName, diagnostics, context);
}
if (constraintsAnnotation == null) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eClassifier, context);
String message = StringUtil.bind(MISSING_CONSTRAINTS, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eClassifier }));
}
else {
allOk = false;
}
}
else {
Set<String> ecoreConstraints = new HashSet<String>(EcoreUtil.getConstraints(eClassifier));
Set<String> oclConstraints = new HashSet<String>(details.keySet());
oclConstraints.removeAll(ecoreConstraints);
ecoreConstraints.removeAll(details.keySet());
for (String aConstraint : oclConstraints) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eClassifier, context);
String message = StringUtil.bind(MISSING_CONSTRAINTS_ANNOTATION_ENTRY, aConstraint, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eClassifier }));
}
else {
allOk = false;
}
}
for (String aConstraint : ecoreConstraints) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eClassifier, context);
String message = StringUtil.bind(EXTRA_CONSTRAINTS_ANNOTATION_ENTRY, aConstraint, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.WARNING, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eClassifier }));
}
else {
allOk = false;
}
}
}
}
return allOk;
}
protected boolean validateEPackage(@NonNull EPackage ePackage, DiagnosticChain diagnostics, @NonNull Map<Object, Object> context) {
boolean allOk = true;
boolean needsInvocationDelegates = false;
boolean needsSettingDelegates = false;
boolean needsValidationDelegates = false;
for (EClassifier eClassifier : ePackage.getEClassifiers()) {
if (OCLCommon.getDelegateAnnotation(eClassifier) != null) {
needsValidationDelegates = true;
}
if (eClassifier instanceof EClass) {
EClass eClass = (EClass)eClassifier;
for (EOperation eOperation : eClass.getEOperations()) {
if (OCLCommon.getDelegateAnnotation(eOperation) != null) {
needsInvocationDelegates = true;
}
}
for (EStructuralFeature eStructuralFeature : eClass.getEStructuralFeatures()) {
if (OCLCommon.getDelegateAnnotation(eStructuralFeature) != null) {
needsSettingDelegates = true;
}
}
}
}
boolean hasInvocationDelegates = isOCL(EcoreUtil.getInvocationDelegates(ePackage));
boolean hasSettingDelegates = isOCL(EcoreUtil.getSettingDelegates(ePackage));
boolean hasValidationDelegates = isOCL(EcoreUtil.getValidationDelegates(ePackage));
if (needsInvocationDelegates && !hasInvocationDelegates) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(ePackage, context);
String message = StringUtil.bind(MISSING_DELEGATE, InvocationBehavior.NAME, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { ePackage }));
}
else {
allOk = false;
}
}
if (needsSettingDelegates && !hasSettingDelegates) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(ePackage, context);
String message = StringUtil.bind(MISSING_DELEGATE, SettingBehavior.NAME, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { ePackage }));
}
else {
allOk = false;
}
}
if (needsValidationDelegates && !hasValidationDelegates) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(ePackage, context);
String message = StringUtil.bind(MISSING_DELEGATE, ValidationBehavior.NAME, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { ePackage }));
}
else {
allOk = false;
}
}
return allOk;
}
protected boolean validateEOperation(@NonNull EOperation eOperation, DiagnosticChain diagnostics, @NonNull Map<Object, Object> context) {
boolean allOk = true;
EAnnotation eAnnotation = OCLCommon.getDelegateAnnotation(eOperation);
if (eAnnotation != null) {
OCLInternal ocl = getOCL(context);
MetamodelManagerInternal metamodelManager = ocl.getMetamodelManager();
StandardLibrary standardLibrary = ocl.getStandardLibrary();
EMap<String, String> details = eAnnotation.getDetails();
Set<String> knownKeys = new HashSet<String>();
if (details.containsKey(InvocationBehavior.BODY_CONSTRAINT_KEY)) {
knownKeys.add(InvocationBehavior.BODY_CONSTRAINT_KEY);
String value = details.get(InvocationBehavior.BODY_CONSTRAINT_KEY);
Type requiredType = EcoreUtil.isInvariant(eOperation) ? standardLibrary.getBooleanType() : null;
allOk = validateExpression(metamodelManager, eOperation, value, requiredType, InvocationBehavior.BODY_CONSTRAINT_KEY, diagnostics, context);
}
if (details.containsKey("pre")) {
knownKeys.add("pre");
String value = details.get("pre");
allOk = validateExpression(metamodelManager, eOperation, value, standardLibrary.getBooleanType(), "pre", diagnostics, context);
}
if (details.containsKey("post")) {
knownKeys.add("post");
String value = details.get("post");
allOk = validateExpression(metamodelManager, eOperation, value, standardLibrary.getBooleanType(), "post", diagnostics, context);
}
Set<String> actualKeys = details.keySet();
Set<String> unknownKeys = new HashSet<String>(actualKeys);
unknownKeys.removeAll(knownKeys);
if (unknownKeys.size() > 0) {
if (diagnostics != null) {
for (String unknownKey : unknownKeys) {
String objectLabel = EObjectValidator.getObjectLabel(eOperation, context);
String message = StringUtil.bind(UNKNOWN_DETAIL, unknownKey, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eOperation }));
}
}
else {
allOk = false;
}
}
}
return allOk;
}
protected boolean validateEStructuralFeature(@NonNull EStructuralFeature eStructuralFeature, DiagnosticChain diagnostics, @NonNull Map<Object, Object> context) {
boolean allOk = true;
EAnnotation eAnnotation = OCLCommon.getDelegateAnnotation(eStructuralFeature);
if (eAnnotation != null) {
EMap<String, String> details = eAnnotation.getDetails();
int entries = 0;
String value = null;
if (details.containsKey(SettingBehavior.DERIVATION_CONSTRAINT_KEY)) {
entries++;
value = details.get(SettingBehavior.DERIVATION_CONSTRAINT_KEY);
}
if (details.containsKey(SettingBehavior.INITIAL_CONSTRAINT_KEY)) {
entries++;
value = details.get(SettingBehavior.INITIAL_CONSTRAINT_KEY);
}
if (entries == 0) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eStructuralFeature, context);
String message = StringUtil.bind(MISSING_PROPERTY_KEY, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eStructuralFeature }));
}
else {
allOk = false;
}
}
else if (entries == 2) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eStructuralFeature, context);
String message = StringUtil.bind(DOUBLE_PROPERTY_KEY, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eStructuralFeature }));
}
else {
allOk = false;
}
}
else if (details.size() != 1) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eStructuralFeature, context);
String message = StringUtil.bind(EXTRA_PROPERTY_KEY, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.WARNING, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eStructuralFeature }));
}
else {
allOk = false;
}
}
else if (value == null) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eStructuralFeature, context);
String message = StringUtil.bind(NULL_PROPERTY_KEY, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.WARNING, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eStructuralFeature }));
}
else {
allOk = false;
}
}
else {
OCLInternal ocl = getOCL(context);
MetamodelManagerInternal metamodelManager = ocl.getMetamodelManager();
allOk = validateExpression(metamodelManager, eStructuralFeature, value, null, null, diagnostics, context);
}
}
return allOk;
}
protected boolean validateExpression(@NonNull MetamodelManagerInternal metamodelManager, @NonNull ENamedElement eNamedElement, @Nullable String expression, @Nullable Type requiredType, @Nullable String role, DiagnosticChain diagnostics, @NonNull Map<Object, Object> context) {
if (expression == null) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eNamedElement, context);
String message = StringUtil.bind(NULL_EXPRESSION, objectLabel);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eNamedElement }));
return true;
}
else {
return false;
}
}
try {
NamedElement asNamedElement = metamodelManager.getASOf(NamedElement.class, eNamedElement);
if (asNamedElement != null) {
ParserContext parserContext = metamodelManager.createParserContext(asNamedElement);
if (parserContext == null) {
throw new ParserException(PivotMessagesInternal.UnknownContextType_ERROR_, NameUtil.qualifiedNameFor(asNamedElement), PivotConstantsInternal.OWNED_CONSTRAINT_ROLE);
}
ExpressionInOCL expressionInOCL = parserContext.parse(asNamedElement, expression);
Type asExpressionType = expressionInOCL.getType();
Type asType;
if (requiredType != null) {
asType = requiredType;
}
else if (asNamedElement instanceof TypedElement) {
asType = ((TypedElement)asNamedElement).getType();
}
else {
asType = null;
}
assert asType != null;
assert asExpressionType != null;
if (!metamodelManager.conformsTo(asExpressionType, TemplateParameterSubstitutions.EMPTY, asType, TemplateParameterSubstitutions.EMPTY)) {
// metamodelManager.conformsTo(asExpressionType, TemplateParameterSubstitutions.EMPTY, asType, TemplateParameterSubstitutions.EMPTY); // Debugging
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eNamedElement, context);
String message = role == null ? StringUtil.bind(INCOMPATIBLE_TYPE_1, asExpressionType, objectLabel)
: StringUtil.bind(INCOMPATIBLE_TYPE_2, asExpressionType, objectLabel, role);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eNamedElement }));
}
else {
return false;
}
}
}
}
catch (ParserException e) {
if (diagnostics != null) {
String objectLabel = EObjectValidator.getObjectLabel(eNamedElement, context);
String message = role == null ? StringUtil.bind(PARSING_ERROR_1, e, objectLabel)
: StringUtil.bind(PARSING_ERROR_2, e, objectLabel, role);
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR, EcoreValidator.DIAGNOSTIC_SOURCE,
0, message, new Object[] { eNamedElement }));
}
else {
return false;
}
}
return true;
}
/**
* Return an OCL AST from a string in the context of a NamedElement. If it is necessary
* to parse OCL concrete syntax and errors result, a ParserException is thrown.
*
public static @NonNull ExpressionInOCL getValidExpressionInOCL(@NonNull MetamodelManager metamodelManager, @NonNull NamedElement contextElement, @NonNull String expression) throws ParserException {
// Resource resource = contextElement.eResource();
// if (resource == null) {
// throw new ParserException("No containing resource for " + contextElement);
// }
// ResourceSet resourceSet = ClassUtil.nonNullState(resource.getResourceSet());
// MetamodelManager metamodelManager = MetamodelManager.getAdapter(resourceSet);
ParserContext parserContext = metamodelManager.getParserContext(contextElement);
if (parserContext == null) {
throw new ParserException(OCLMessages.UnknownContextType_ERROR_, EcoreUtils.qualifiedNameFor(contextElement), PivotConstants.UNKNOWN_ROLE/*getSpecificationRole(specification)* /);
}
// Namespace contextElement2 = PivotUtil.getContainingNamespace(contextElement);
// if (contextElement == null) {
// throw new ParserException("No containing namespace for " + contextElement);
// }
Type classContext = parserContext.getClassContext();
// assert classContext == contextElement2;
ExpressionInOCL expressionInOCL = parserContext.parse(classContext, expression);
return expressionInOCL;
} */
}