blob: 34a3a63c9f9b9eb17bed5bd00fa125fa2d07ce59 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2018 CEA LIST and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink (CEA LIST) - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.examples.validity.locator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.common.util.Monitor;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.impl.EStringToStringMapEntryImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.common.OCLCommon;
import org.eclipse.ocl.examples.emf.validation.validity.LeafConstrainingNode;
import org.eclipse.ocl.examples.emf.validation.validity.Result;
import org.eclipse.ocl.examples.emf.validation.validity.ResultConstrainingNode;
import org.eclipse.ocl.examples.emf.validation.validity.Severity;
import org.eclipse.ocl.examples.emf.validation.validity.ValidatableNode;
import org.eclipse.ocl.examples.emf.validation.validity.locator.ConstraintLocator;
import org.eclipse.ocl.examples.emf.validation.validity.manager.ValidityManager;
import org.eclipse.ocl.examples.emf.validation.validity.manager.ValidityModel;
import org.eclipse.ocl.examples.validity.plugin.OCLValidityPlugin;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.evaluation.AbstractConstraintEvaluator;
import org.eclipse.ocl.pivot.evaluation.EvaluationVisitor;
import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager;
import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal;
import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal.EnvironmentFactoryInternalExtension;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.ParserException;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
public class DelegateConstraintLocator extends AbstractPivotConstraintLocator
{
public static @NonNull DelegateConstraintLocator INSTANCE = new DelegateConstraintLocator();
protected @Nullable Constraint getConstraint(@NonNull PivotMetamodelManager metamodelManager, @NonNull ResultConstrainingNode resultConstrainingNode) throws ParserException {
Object constrainingObject = resultConstrainingNode.getParent().getConstrainingObject();
if (constrainingObject instanceof EAnnotation) {
EObject eObject = ((EAnnotation) constrainingObject).eContainer();
if (eObject instanceof EOperation) {
return ((EnvironmentFactoryInternalExtension)metamodelManager.getEnvironmentFactory()).getASOf(Constraint.class, eObject);
}
}
else if (constrainingObject instanceof EStringToStringMapEntryImpl) {
EStringToStringMapEntryImpl eEntry = (EStringToStringMapEntryImpl)constrainingObject;
EObject eAnnotation = eEntry.eContainer();
if (eAnnotation instanceof EAnnotation) {
EObject eClassifier = ((EAnnotation)eAnnotation).eContainer();
if (eClassifier instanceof EClassifier) {
org.eclipse.ocl.pivot.Class asType = ((EnvironmentFactoryInternalExtension)metamodelManager.getEnvironmentFactory()).getASOf(org.eclipse.ocl.pivot.Class.class, eClassifier);
if (asType != null) {
return NameUtil.getNameable(asType.getOwnedInvariants(), eEntry.getKey());
}
}
}
}
return null;
}
protected EObject getConstrainedObject(@NonNull ResultConstrainingNode resultConstrainingNode) {
ValidatableNode validatableNode = resultConstrainingNode.getResultValidatableNode().getParent();
assert validatableNode != null;
return validatableNode.getConstrainedObject();
}
@Override
public @Nullable Map<@NonNull EObject, @NonNull List<@NonNull LeafConstrainingNode>> getConstraints(@NonNull ValidityModel validityModel,
@NonNull EPackage ePackage, @NonNull Set<@NonNull Resource> resources, @NonNull Monitor monitor) {
if (ePackage.eContainer() instanceof EAnnotation) { // Applied UML Profiles are UML not Ecore constraints
return null;
}
Map<@NonNull EObject, @NonNull List<@NonNull LeafConstrainingNode>> map = null;
for (@SuppressWarnings("null")@NonNull EClassifier eClassifier : ePackage.getEClassifiers()) {
if (monitor.isCanceled()) {
return null;
}
EAnnotation oclAnnotation = OCLCommon.getDelegateAnnotation(eClassifier);
if (oclAnnotation != null) {
EMap<String, String> details = oclAnnotation.getDetails();
for (@SuppressWarnings("null")Map.@NonNull Entry<String, String> constraint : details.entrySet()) {
String constraintName = constraint.getKey();
if (constraintName != null) {
map = createLeafConstrainingNode(map, validityModel, eClassifier, constraint, constraintName);
}
}
}
if (eClassifier instanceof EClass) {
for (@SuppressWarnings("null")@NonNull EOperation eOperation : ((EClass)eClassifier).getEOperations()) {
if (EcoreUtil.isInvariant(eOperation)) {
oclAnnotation = OCLCommon.getDelegateAnnotation(eOperation);
if (oclAnnotation != null) {
String constraintBody = oclAnnotation.getDetails().get("body");
if (constraintBody != null) {
String constraintName = eOperation.getName();
if (constraintName != null) {
map = createLeafConstrainingNode(map, validityModel, eClassifier, oclAnnotation, constraintName);
}
}
}
}
}
}
}
return map;
}
@Override
public Object getImage() {
return OCLValidityPlugin.INSTANCE.getImage("OCLModelFile.gif"); // FIXME something better
}
@Override
public @NonNull ConstraintLocator getInstance() {
return INSTANCE;
}
@Override
public @NonNull String getName() {
return "Delegated OCL constraints";
}
@Override
public @Nullable String getSourceExpression(@NonNull LeafConstrainingNode node) {
Object constrainingObject = node.getConstrainingObject();
if (constrainingObject instanceof EAnnotation) {
return ((EAnnotation)constrainingObject).getDetails().get("body");
}
else if (constrainingObject instanceof EStringToStringMapEntryImpl) {
return ((EStringToStringMapEntryImpl)constrainingObject).getValue();
}
else {
return null;
}
}
protected @NonNull String print(@NonNull Map<EClassifier, @NonNull List<LeafConstrainingNode>> map) {
StringBuilder s = new StringBuilder();
ArrayList<EClassifier> sortedList = new ArrayList<EClassifier>(map.keySet());
Collections.sort(sortedList, new Comparator<EClassifier>()
{
@Override
public int compare(EClassifier o1, EClassifier o2) {
return o1.getName().compareTo(o2.getName());
}
});
for (EClassifier eClassifier : sortedList) {
s.append("\t" + eClassifier.getName() + ":");
List<LeafConstrainingNode> constraints = map.get(eClassifier);
assert constraints != null;
for (LeafConstrainingNode constraint : constraints) {
s.append(" \'" + constraint.getLabel() + "'");
}
s.append("\n");
}
return s.toString();
}
@Override
public void validate(@NonNull Result result, @NonNull ValidityManager validityManager, @Nullable Monitor monitor) {
EObject constrainedObject = result.getValidatableNode().getConstrainedObject();
Resource eResource = constrainedObject.eResource();
if (eResource == null) {
return;
}
ResultConstrainingNode resultConstrainingNode = result.getResultConstrainingNode();
if (resultConstrainingNode == null) {
return;
}
EnvironmentFactoryInternal environmentFactory = PivotUtilInternal.getEnvironmentFactory(eResource);
PivotMetamodelManager metamodelManager = environmentFactory.getMetamodelManager();
Constraint asConstraint = null;
try {
asConstraint = getConstraint(metamodelManager, resultConstrainingNode);
} catch (ParserException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Severity severity = Severity.UNKNOWN;
try {
if (asConstraint == null) {
throw new ParserException("Failed to create pivot Constraint");
}
final Constraint finalConstraint = asConstraint;
ExpressionInOCL query = getQuery(metamodelManager, asConstraint);
EvaluationVisitor evaluationVisitor = createEvaluationVisitor(environmentFactory, query, constrainedObject, monitor);
AbstractConstraintEvaluator<Diagnostic> constraintEvaluator = new AbstractConstraintLocator(metamodelManager, query, constrainedObject)
{
@Override
protected String getObjectLabel() {
org.eclipse.ocl.pivot.Type type = PivotUtil.getContainingType(finalConstraint);
org.eclipse.ocl.pivot.Type primaryType = type != null ? metamodelManager.getPrimaryType(type) : null;
EClassifier classifier = primaryType != null ? (EClassifier)primaryType.getESObject() : null;
return classifier != null ? classifier.getName() : "??";
// return ClassUtil.getLabel(classifier, object, context);
}
};
Diagnostic diagnostic = constraintEvaluator.evaluate(evaluationVisitor);
result.setDiagnostic(diagnostic);
severity = diagnostic != null ? getSeverity(diagnostic) : Severity.OK;
} catch (Throwable e) {
result.setException(e);
severity = Severity.FATAL;
} finally {
result.setSeverity(severity);
}
}
}