blob: 9311036cf0753691f4912d632f1f362363dfb68d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 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.Collection;
import java.util.HashSet;
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.Monitor;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
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.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.ConstrainingURI;
import org.eclipse.ocl.examples.emf.validation.validity.manager.TypeURI;
import org.eclipse.ocl.examples.emf.validation.validity.manager.ValidityManager;
import org.eclipse.ocl.examples.emf.validation.validity.manager.ValidityModel;
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.EnvironmentFactoryInternalExtension;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.utilities.ParserException;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.OpaqueExpression;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageImport;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.ValueSpecification;
public class UMLConstraintLocator extends AbstractPivotConstraintLocator
{
public static @NonNull UMLConstraintLocator INSTANCE = new UMLConstraintLocator();
protected void appendPath(@NonNull StringBuilder s, @NonNull NamedElement eObject) {
EObject eContainer = eObject.eContainer();
if (eContainer instanceof NamedElement) {
appendPath(s, (NamedElement)eContainer);
s.append("::");
}
s.append(eObject.getName());
}
@Override
public @NonNull Set<@NonNull TypeURI> getAllTypes(@NonNull ValidityManager validityManager, @NonNull EObject constrainingType) {
if (constrainingType instanceof org.eclipse.uml2.uml.Class) {
Set<@NonNull TypeURI> allTypes = new HashSet<@NonNull TypeURI>();
allTypes.add(validityManager.getTypeURI(constrainingType));
if (constrainingType instanceof org.eclipse.uml2.uml.Class) {
getAllTypes(allTypes, validityManager, ((org.eclipse.uml2.uml.Class)constrainingType).getSuperClasses());
}
return allTypes;
}
else {
return super.getAllTypes(validityManager, constrainingType);
}
}
private void getAllTypes(Set<@NonNull TypeURI> knownTypes, @NonNull ValidityManager validityManager, Iterable<org.eclipse.uml2.uml.Class> moreTypes) {
for (org.eclipse.uml2.uml.Class anotherType : moreTypes) {
if ((anotherType != null) && knownTypes.add(validityManager.getTypeURI(anotherType))) {
getAllTypes(knownTypes, validityManager, anotherType.getSuperClasses());
}
}
}
@Override // FIXME is it getConstrainingURI or getTypeURI that needs the overload - no JUnit test uses the code
public @Nullable ConstrainingURI getConstrainingURI(@NonNull EObject eObject) {
EObject eContainer = eObject;
for ( ; true; eContainer = eContainer.eContainer()) {
if (eContainer == null) {
return null;
}
if (eContainer instanceof Package) {
break;
}
}
String nsURI = null;
Stereotype appliedStereotype = ((Package)eContainer).getAppliedStereotype("Ecore::EPackage");
if (appliedStereotype != null) {
Object value = ((Package)eContainer).getValue(appliedStereotype, "nsURI");
if (value != null) {
nsURI = value.toString();
}
}
if (nsURI == null) {
nsURI = ((Package)eContainer).getURI();
}
if (nsURI == null) {
return null;
}
Resource resource = eObject.eResource();
if (resource == null) {
return null;
}
String uriFragment = resource.getURIFragment(eObject);
if (uriFragment == null) {
return null;
}
if (!uriFragment.startsWith("//")) {
uriFragment = "//" + uriFragment; // FIXME regularize this ?? UML2Ecore
}
@NonNull URI constrainingURI = URI.createURI(nsURI).appendFragment(uriFragment);
return new ConstrainingURI(constrainingURI);
}
@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) {
Map<@NonNull EObject, @NonNull List<@NonNull LeafConstrainingNode>> map = null;
for (@NonNull Resource resource : resources) {
if (monitor.isCanceled()) {
return null;
}
for (TreeIterator<EObject> tit = resource.getAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (eObject instanceof Constraint) {
Constraint umlConstraint = (Constraint)eObject;
Element contextElement = umlConstraint.getContext();
if (contextElement instanceof Type) {
@NonNull String label = String.valueOf(umlConstraint.getName());
/* LeafConstrainingNode constraint = validityModel.createLeafConstrainingNode();
constraint.setConstraintLocator(this);
constraint.setConstrainingObject(umlConstraint);
constraint.setLabel(label);
ConstrainingNode constrainingNode = validityModel.getConstrainingNode(constrainedElement);
constrainingNode.getChildren().add(constraint);
if (map == null) {
map = new HashMap<EModelElement, List<LeafConstrainingNode>>();
}
List<LeafConstrainingNode> constraints = map.get(constrainedElement);
if (constraints == null) {
constraints = new ArrayList<LeafConstrainingNode>();
map.put(constrainedElement, constraints);
}
constraints.add(constraint); */
// EClass eC = constrainedElement.eClass();
map = createLeafConstrainingNode(map, validityModel, contextElement, umlConstraint, label);
}
}
if (monitor.isCanceled()) {
return null;
}
}
}
return map;
}
@Override
public @Nullable Collection<@NonNull Resource> getImports(@NonNull EPackage ePackage, @NonNull Resource resource) {
Set<@NonNull Resource> imports = new HashSet<@NonNull Resource>();
for (TreeIterator<EObject> tit = resource.getAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (eObject instanceof PackageImport) {
PackageImport umlPackageImport = (PackageImport)eObject;
Package importedPackage = umlPackageImport.getImportedPackage();
if (importedPackage != null) {
Resource eResource = importedPackage.eResource();
if (eResource != null) {
imports.add(eResource);
}
}
// tit.prune();
}
// else if (eObject instanceof Type) {
// tit.prune();
// }
Resource eResource = eObject.eClass().eResource();
if (eResource != null) {
imports.add(eResource);
}
}
return imports;
}
@Override
public @NonNull ConstraintLocator getInstance() {
return INSTANCE;
}
@Override
public @NonNull String getLabel(@NonNull EModelElement eObject) {
if (eObject instanceof NamedElement) { // FIXME debugging - remove UML dependency
StringBuilder s = new StringBuilder();
appendPath(s, (NamedElement)eObject);
return s.toString();
}
else {
return super.getLabel(eObject);
}
}
@Override
public @NonNull String getName() {
return "UML Constraints";
}
@Override
public @Nullable String getSourceExpression(@NonNull LeafConstrainingNode node) {
Object constrainingObject = node.getConstrainingObject();
if (!(constrainingObject instanceof Constraint)) {
return null;
}
ValueSpecification specification = ((Constraint)constrainingObject).getSpecification();
if (!(specification instanceof OpaqueExpression)) {
return null;
}
List<String> bodies = ((OpaqueExpression)specification).getBodies();
return bodies.size() > 0 ? bodies.get(0) : null;
}
@Override
public @Nullable Resource getSourceResource(@NonNull LeafConstrainingNode node) {
Object constrainingObject = node.getConstrainingObject();
if (!(constrainingObject instanceof EObject)) {
return null;
}
return ((EObject)constrainingObject).eResource();
}
@Override
public @Nullable TypeURI getTypeURI(@NonNull EObject eObject) {
EObject eContainer = eObject;
for ( ; true; eContainer = eContainer.eContainer()) {
if (eContainer == null) {
return null;
}
if (eContainer instanceof Package) {
break;
}
}
String nsURI = null;
Stereotype appliedStereotype = ((Package)eContainer).getAppliedStereotype("Ecore::EPackage");
if (appliedStereotype != null) {
Object value = ((Package)eContainer).getValue(appliedStereotype, "nsURI");
if (value != null) {
nsURI = value.toString();
}
}
if (nsURI == null) {
nsURI = ((Package)eContainer).getURI();
}
if (nsURI == null) {
return null;
}
Resource resource = eObject.eResource();
if (resource == null) {
return null;
}
String uriFragment = resource.getURIFragment(eObject);
if (!uriFragment.startsWith("//")) {
uriFragment = "//" + uriFragment; // FIXME regularize this ?? UML2Ecore
}
@NonNull URI typeURI = URI.createURI(nsURI).appendFragment(uriFragment);
return new TypeURI(typeURI);
}
@Override
public @Nullable Set<@NonNull TypeURI> getTypeURIs(@NonNull ValidityManager validityManager, @NonNull EObject validatableObject) {
EClass eClass = validatableObject.eClass();
if (eClass != null) {
EAnnotation eAnnotation = eClass.getEAnnotation("http://www.eclipse.org/uml2/2.0.0/UML");
if ((eAnnotation != null) && (eAnnotation.getReferences().size() > 0)) { // Stereotype application
EObject umlClass = eAnnotation.getReferences().get(0);
if (umlClass != null) {
Set<@NonNull TypeURI> allTypeURIs = new HashSet<@NonNull TypeURI>();
TypeURI typeURI = validityManager.getTypeURI(umlClass);
allTypeURIs.add(typeURI);
return allTypeURIs;
}
}
}
if (validatableObject instanceof InstanceSpecification) {
Set<@NonNull TypeURI> allTypeURIs = new HashSet<@NonNull TypeURI>();
for (org.eclipse.uml2.uml.Classifier umlClassifier : ((InstanceSpecification)validatableObject).getClassifiers()) {
if (umlClassifier != null) {
TypeURI typeURI = validityManager.getTypeURI(umlClassifier);
allTypeURIs.add(typeURI);
}
}
return allTypeURIs;
}
return null;
}
@Override
public void validate(@NonNull Result result, @NonNull ValidityManager validityManager, @Nullable Monitor monitor) {
ValidatableNode validatableNode = result.getValidatableNode();
EObject contextObject = validatableNode.getConstrainedObject();
LeafConstrainingNode leafConstrainingNode = result.getLeafConstrainingNode();
org.eclipse.uml2.uml.Constraint umlConstraint = (org.eclipse.uml2.uml.Constraint)leafConstrainingNode.getConstrainingObject();
if (umlConstraint == null) {
return;
}
EnvironmentFactoryInternalExtension environmentFactory = (EnvironmentFactoryInternalExtension) PivotUtilInternal.findEnvironmentFactory(umlConstraint);
if (environmentFactory == null) {
Resource eResource = umlConstraint.eResource();
if (eResource == null) {
return;
}
environmentFactory = (EnvironmentFactoryInternalExtension) PivotUtilInternal.getEnvironmentFactory(eResource);
}
PivotMetamodelManager metamodelManager = environmentFactory.getMetamodelManager();
Severity severity = Severity.UNKNOWN;
try {
final org.eclipse.ocl.pivot.Constraint pivotConstraint = environmentFactory.getASOf(org.eclipse.ocl.pivot.Constraint.class, umlConstraint);
if (pivotConstraint == null) {
throw new ParserException("Failed to create pivot Constraint");
}
ResourceSet resourceSet = contextObject.eResource().getResourceSet();
if (resourceSet != null) {
ExpressionInOCL query = getQuery(metamodelManager, pivotConstraint);
EvaluationVisitor evaluationVisitor = createEvaluationVisitor(environmentFactory, query, contextObject, monitor);
AbstractConstraintEvaluator<Diagnostic> constraintEvaluator = new AbstractConstraintLocator(metamodelManager, query, contextObject)
{
@Override
protected String getObjectLabel() {
org.eclipse.ocl.pivot.Type type = PivotUtil.getContainingType(pivotConstraint);
return type != null ? type.getName() : "??";
}
};
@Nullable 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);
}
}
}