/******************************************************************************* * Copyright (c) 2013, 2015 CEA LIST 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 (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; 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; } EnvironmentFactoryInternal environmentFactory = PivotUtilInternal.findEnvironmentFactory(umlConstraint); if (environmentFactory == null) { Resource eResource = umlConstraint.eResource(); if (eResource == null) { return; } environmentFactory = PivotUtilInternal.getEnvironmentFactory(eResource); } PivotMetamodelManager metamodelManager = environmentFactory.getMetamodelManager(); Severity severity = Severity.UNKNOWN; try { final org.eclipse.ocl.pivot.Constraint pivotConstraint = metamodelManager.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); } } }