blob: 2633ed2489656b82dac9f50aef6bbeab338190d9 [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
* Obeo - Manage the Navigation from the ValidityView -> to the Editor
*******************************************************************************/
package org.eclipse.ocl.examples.emf.validation.validity.manager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.Monitor;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.impl.DynamicEObjectImpl;
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.AbstractNode;
import org.eclipse.ocl.examples.emf.validation.validity.ConstrainingNode;
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.ResultSet;
import org.eclipse.ocl.examples.emf.validation.validity.ResultValidatableNode;
import org.eclipse.ocl.examples.emf.validation.validity.RootConstrainingNode;
import org.eclipse.ocl.examples.emf.validation.validity.RootNode;
import org.eclipse.ocl.examples.emf.validation.validity.RootValidatableNode;
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.ValidityFactory;
import org.eclipse.ocl.examples.emf.validation.validity.locator.ConstraintLocator;
import org.eclipse.ocl.examples.emf.validation.validity.utilities.IVisibilityFilter;
import org.eclipse.ocl.examples.emf.validation.validity.utilities.SeveritiesVisibilityFilter;
import org.eclipse.ocl.pivot.labels.ILabelGenerator;
import org.eclipse.ocl.pivot.util.DerivedConstants;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
public class ValidityModel
{
private static final Logger logger = Logger.getLogger(ValidityManager.class);
public static final int WORK_FOR_CLEAN_UP = 50;
public static final int WORK_FOR_CREATE_MODEL = 50;
private static final int WORK_FOR_ANALYZE_RESOURCES = 300;
private static final int WORK_FOR_LOCATE_CONSTRAINTS = 300;
private static final int WORK_FOR_CREATE_RESULTS = 300;
private static final int WORK_FOR_SORT_CONSTRAINING_NODES = 50;
private static final int WORK_FOR_SORT_VALIDATABLE_NODES = 50;
public static final int WORK_FOR_ALL_SET_INPUT = WORK_FOR_CLEAN_UP +
WORK_FOR_CREATE_MODEL + WORK_FOR_ANALYZE_RESOURCES +
WORK_FOR_LOCATE_CONSTRAINTS + WORK_FOR_CREATE_RESULTS +
WORK_FOR_SORT_CONSTRAINING_NODES + WORK_FOR_SORT_VALIDATABLE_NODES;
private static @NonNull Comparator<@NonNull AbstractNode> labelComparator = new Comparator<@NonNull AbstractNode>()
{
@Override
public int compare(@NonNull AbstractNode o1, @NonNull AbstractNode o2) {
String l1 = o1.getLabel();
String l2 = o2.getLabel();
return l1.compareTo(l2);
}
};
private static @NonNull Comparator<@NonNull AbstractNode> natureComparator = new Comparator<@NonNull AbstractNode>()
{
@Override
public int compare(@NonNull AbstractNode o1, @NonNull AbstractNode o2) {
EClass c1 = o1.eClass();
EClass c2 = o2.eClass();
if (c1 == c2) {
return o1.getLabel().compareTo(o2.getLabel());
}
String l1 = c1.getName();
String l2 = c2.getName();
return l1.compareTo(l2);
}
};
private static @Nullable Set<@NonNull ConstraintLocator> badConstraintLocators = null;
protected final @NonNull ValidityManager validityManager;
private final @NonNull RootNode rootNode = ValidityFactory.eINSTANCE.createRootNode();
private final @NonNull Map<@NonNull ConstrainingURI, @NonNull ConstrainingNode> allConstrainingNodes = new HashMap<@NonNull ConstrainingURI, @NonNull ConstrainingNode>();
private final @NonNull Map<@NonNull ValidatableURI, @NonNull ValidatableNode> allValidatableNodes = new HashMap<@NonNull ValidatableURI, @NonNull ValidatableNode>();
private final @NonNull Set<@NonNull IVisibilityFilter> validatableFilters = new HashSet<@NonNull IVisibilityFilter>();
private final @NonNull Set<@NonNull IVisibilityFilter> constrainingFilters = new HashSet<@NonNull IVisibilityFilter>();
private final @NonNull SeveritiesVisibilityFilter constrainingNodesFilterByKind = new SeveritiesVisibilityFilter();
private final @NonNull SeveritiesVisibilityFilter validatableNodesFilterByKind = new SeveritiesVisibilityFilter();
private final @NonNull Map<@NonNull TypeURI, @NonNull Set<@NonNull TypeURI>> typeClosures = new HashMap<@NonNull TypeURI, @NonNull Set<@NonNull TypeURI>>();
private final @NonNull Collection<@NonNull Resource> resources;
/**
* Map from the URI of a type to be validated to the Constraining URIs of the types that provide constraints on instances of the type.
*/
private final @NonNull Map<@NonNull TypeURI, List<@NonNull ConstrainingURI>> type2constrainingType = new HashMap<@NonNull TypeURI, @NonNull List<@NonNull ConstrainingURI>>();
/**
* The Constructor.
*
* @param validityManager
* The ValidityManager
* @param newResources
* All resources found in the resourceSet
*/
public ValidityModel(@NonNull ValidityManager validityManager, @NonNull Collection<@NonNull Resource> newResources) {
this.validityManager = validityManager;
this.resources = newResources;
}
public @Nullable Set<@NonNull ConstrainingURI> accumulateConstrainingURIs(@Nullable Set<@NonNull ConstrainingURI> constrainingURIs, @NonNull TypeURI typeURI) {
List<@NonNull ConstrainingURI> moreConstrainingURIs = type2constrainingType.get(typeURI);
if (moreConstrainingURIs != null) {
if (constrainingURIs == null) {
constrainingURIs = new HashSet<@NonNull ConstrainingURI>();
}
constrainingURIs.addAll(moreConstrainingURIs);
}
return constrainingURIs;
}
public void addConstrainingFilter(@NonNull IVisibilityFilter filter) {
constrainingFilters.add(filter);
}
public void addFilteredSeverity(@NonNull Severity severity) {
constrainingNodesFilterByKind.addFilteredSeverity(severity);
addConstrainingFilter(constrainingNodesFilterByKind);
validatableNodesFilterByKind.addFilteredSeverity(severity);
addValidatableFilter(validatableNodesFilterByKind);
}
public void addValidatableFilter(@NonNull IVisibilityFilter filter) {
validatableFilters.add(filter);
}
/**
* Looks for all EPackages in the source Resources.
*
* @param resources
* the Collection of all resources in the resourceSet
* @return a map containing all EPackages of all resources
*/
protected @NonNull Map<@NonNull EPackage, @NonNull Set<@NonNull Resource>> analyzeResources(@NonNull Collection<@NonNull Resource> resources, @NonNull Monitor monitor, int worked) {
monitor.setTaskName("Analyzing Resources");
MonitorStep monitorStep = new MonitorStep(monitor, worked);
try {
List<@NonNull Resource> allResources = new ArrayList<@NonNull Resource>(resources);
Map<@NonNull EPackage, @NonNull Set<@NonNull Resource>> ePackage2resources = new HashMap<@NonNull EPackage, @NonNull Set<@NonNull Resource>>();
int allResourcesCount = allResources.size();
for (int i = 0; i < allResourcesCount; i++) {
Resource resource = ClassUtil.nonNull(allResources.get(i));
@NonNull String uri = String.valueOf(resource.getURI());
monitor.subTask("'" + uri + "'");
ValidityManager.ANALYZE_RESOURCE.println(uri);
Set<@NonNull EClass> eClasses;
ResourceSet resourceSet = resource.getResourceSet();
if (resourceSet != null) {
synchronized (resourceSet) { // See Bug 405072 for rationale that avoids CMEs as UML stereotypes are discovered lazily
eClasses = analyzeResource(resource);
}
}
else {
eClasses = analyzeResource(resource);
}
Set<@NonNull EPackage> ePackages = new HashSet<@NonNull EPackage>();
for (@NonNull EClass eClass : eClasses) {
ePackages.add(ClassUtil.nonNull(eClass.getEPackage()));
for (@NonNull EClass eSuperClass : ClassUtil.nullFree(eClass.getEAllSuperTypes())) {
ePackages.add(ClassUtil.nonNull(eSuperClass.getEPackage()));
}
}
for (@NonNull EPackage ePackage : ePackages) {
Set<@NonNull Resource> ePackageResources = ePackage2resources.get(ePackage);
if (ePackageResources == null) {
ePackageResources = new HashSet<@NonNull Resource>();
ePackage2resources.put(ePackage, ePackageResources);
}
ePackageResources.add(resource);
String nsURI = ePackage.getNsURI();
if (nsURI !=null) {
ValidityManager.ANALYZE_RESOURCE.println(" -> " + nsURI);
Iterable<@NonNull ConstraintLocator> list = getConstraintLocators(nsURI);
if (list != null) {
for (ConstraintLocator constraintLocator : list) {
try {
Collection<@NonNull Resource> moreResources = constraintLocator.getImports(ePackage, resource);
if (moreResources != null) {
for (Resource anotherResource : moreResources) {
if (!allResources.contains(anotherResource)) {
allResources.add(anotherResource);
}
}
}
}
catch (Exception e) {
Set<@NonNull ConstraintLocator> badConstraintLocators2 = badConstraintLocators;
if (badConstraintLocators2 == null) {
synchronized (this) {
badConstraintLocators = badConstraintLocators2 = new HashSet<@NonNull ConstraintLocator>();
}
}
if (!badConstraintLocators2.contains(constraintLocator)) {
synchronized (badConstraintLocators2) {
if (badConstraintLocators2.add(constraintLocator)) {
logger.error("ConstraintLocator " + constraintLocator + " failed", e);
}
}
}
}
}
}
}
}
monitorStep.workedFraction(allResourcesCount);
}
return ePackage2resources;
} finally {
monitorStep.done();
}
}
protected @NonNull Set<@NonNull EClass> analyzeResource(Resource resource) {
Set<@NonNull EClass> eClasses = new HashSet<@NonNull EClass>();
for (TreeIterator<EObject> tit = resource.getAllContents(); tit.hasNext(); ) {
@SuppressWarnings("null")@NonNull EObject eObject = tit.next();
@SuppressWarnings("null")@NonNull EClass eClass = eObject.eClass();
eClasses.add(eClass);
}
return eClasses;
}
/**
* Return all types that may provide constraints to an instance of aType.
*/
protected @NonNull Set<@NonNull TypeURI> buildTypeClosure(@NonNull EObject constrainingObject) {
TypeURI typeURI = validityManager.getTypeURI(constrainingObject);
Set<@NonNull TypeURI> typeClosure = typeClosures.get(typeURI);
if (typeClosure == null) {
typeClosure = new HashSet<@NonNull TypeURI>();
typeClosures.put(typeURI, typeClosure);
}
String nsURI = constrainingObject.eClass().getEPackage().getNsURI();
if (nsURI != null) {
Iterable<@NonNull ConstraintLocator> constraintLocators = ValidityManager.getConstraintLocators(nsURI);
if (constraintLocators != null) {
for (ConstraintLocator constraintLocator : constraintLocators) {
StringBuilder s = null;
if (ValidityManager.BUILD_TYPE.isActive()) {
s = new StringBuilder();
s.append("PackageURI \"" + nsURI + "\" using \"" + constraintLocator.getName() + "\"");
s.append("\n ConstraintURI \"" + validityManager.getConstrainingURI(constrainingObject) + "\" applies to");
}
Set<@NonNull TypeURI> allTypes = constraintLocator.getAllTypes(validityManager, constrainingObject);
for (@NonNull TypeURI aType : allTypes) {
if (s != null) {
s.append("\n TypeURI \"" + aType + "\"");
}
typeClosure.add(aType);
}
if (s != null){
ValidityManager.BUILD_TYPE.println(s.toString());
}
}
}
}
return typeClosure;
}
/**
* Creates a ConstrainingNode.
*
* @return the created ConstrainingNode
*/
protected @NonNull ConstrainingNode createConstrainingNode() {
return ValidityFactory.eINSTANCE.createConstrainingNode();
}
/**
* creates a LeafConstrainingNode
*
* @return the created LeafConstrainingNode
*/
public @NonNull LeafConstrainingNode createLeafConstrainingNode() {
return ValidityFactory.eINSTANCE.createLeafConstrainingNode();
}
/**
* Return a new Result object, or return null if the creation process is to be aborted.
* <p>
* The default implementation always return an object. Derived implementations may cancel
* in response to a progress monitor request.
*
* @param monitor the corresponding monitor
* @return the created new Result object
*/
protected @Nullable Result createResult(@Nullable IProgressMonitor monitor) {
return ValidityFactory.eINSTANCE.createResult();
}
/**
* Creates a ResultConstrainingNode.
*
* @return the created ResultConstrainingNode
*/
protected @NonNull ResultConstrainingNode createResultConstrainingNode() {
return ValidityFactory.eINSTANCE.createResultConstrainingNode();
}
/**
* Create the ResultValidatableNode,ResultConstrainingNode cross-linkage for
* all validateableObject,constraint pairs.
*
* @param resources
* the resources
*/
protected void createResultNodes(@NonNull Collection<@NonNull Resource> resources, @NonNull Monitor monitor, int worked) {
monitor.setTaskName("Create Result Nodes");
MonitorStep monitorStep = new MonitorStep(monitor, worked);
try {
int resourcesCount = resources.size();
for (@NonNull Resource resource : resources) {
monitor.subTask("'" + resource.getURI() + "'");
ConstraintLocator constraintLocator = ValidityManager.getConstraintLocator(resource); // Get a resource-specific locator, e.g. the UML stereotype application handler
for (TreeIterator<EObject> tit = resource.getAllContents(); tit.hasNext(); ) { // FIXME there is a CME hazard here
if (monitor.isCanceled()) {
return;
}
@SuppressWarnings("null")@NonNull EObject validatableObject = tit.next();
Set<@NonNull ConstrainingURI> allConstrainingURIs = null;
Set<@NonNull TypeURI> allTypeURIs = null;
// if (validatableObject instanceof DynamicEObjectImpl) {
// allConstrainingURIs = null;
// }
if (constraintLocator != null) {
allTypeURIs = constraintLocator.getTypeURIs(validityManager, validatableObject);
if (allTypeURIs != null) {
for (@NonNull TypeURI typeURI : allTypeURIs) {
Set<@NonNull TypeURI> typeURIs = typeClosures.get(typeURI);
if (typeURIs == null) {
// buildTypeClosure(eClass);
List<TypeURI> typeURIkeys = new ArrayList<TypeURI>(typeClosures.keySet());
Collections.sort(typeURIkeys);
// typeURIs = buildTypeClosure(eClass);
}
if (typeURIs != null) {
for (@NonNull TypeURI typeURI2 : typeURIs) {
if (typeURI2 != null) {
allConstrainingURIs = accumulateConstrainingURIs(allConstrainingURIs, typeURI2);
}
}
}
}
}
}
if (allTypeURIs == null) {
EClass eClass = validatableObject.eClass();
if (eClass != null) {
TypeURI typeURI = validityManager.getTypeURI(eClass);
Set<@NonNull TypeURI> typeURIs = typeClosures.get(typeURI);
if (typeURIs == null) {
buildTypeClosure(eClass);
List<@NonNull TypeURI> typeURIkeys = new ArrayList<@NonNull TypeURI>(typeClosures.keySet());
Collections.sort(typeURIkeys);
typeURIs = buildTypeClosure(eClass);
}
if (typeURIs != null) {
for (@NonNull TypeURI typeURI2 : typeURIs) {
allConstrainingURIs = accumulateConstrainingURIs(allConstrainingURIs, typeURI2);
}
}
}
}
if (allConstrainingURIs != null) {
List<@NonNull ConstrainingURI> sortedURIs = new ArrayList<@NonNull ConstrainingURI>(allConstrainingURIs);
Collections.sort(sortedURIs);
for (@NonNull ConstrainingURI constrainingURI : sortedURIs) {
if (constrainingURI != null) {
createResultNodes(validatableObject, constrainingURI);
}
}
}
}
monitorStep.workedFraction(resourcesCount);
}
} finally {
monitorStep.done();
}
}
/**
* Create the ResultValidatableNode,ResultConstrainingNode cross-linkage
* between constrainedObject and each child constraint of constrainingType.
*
* @param constrainedObject
* the constraining object
* @param constrainingURI
* the uri of the constrainingNode
*/
protected void createResultNodes(@NonNull EObject constrainedObject, @NonNull ConstrainingURI constrainingURI) {
ValidatableNode validatable = getValidatableNode(constrainedObject);
ConstrainingNode constrainingNode = allConstrainingNodes.get(constrainingURI);
if (constrainingNode != null) {
createResultNodes(validatable, constrainingNode);
}
}
protected void createResultNodes(@NonNull ValidatableNode validatable, @NonNull ConstrainingNode constrainingNode) {
List<@NonNull ConstrainingNode> children = ClassUtil.nullFree(constrainingNode.getChildren());
if (children.size() > 0) {
for (@NonNull ConstrainingNode childConstrainingNode : children) {
if (childConstrainingNode instanceof LeafConstrainingNode) {
ResultConstrainingNode resultConstrainingNode = createResultConstrainingNode();
ResultValidatableNode resultValidatableNode = createResultValidatableNode();
resultConstrainingNode.setResultValidatableNode(resultValidatableNode);
resultConstrainingNode.setLabel(getResultConstrainingLabel(validatable));
resultValidatableNode.setLabel(getResultValidatableLabel(childConstrainingNode));
childConstrainingNode.getChildren().add(resultConstrainingNode);
validatable.getChildren().add(resultValidatableNode);
ValidityManager.CREATE_RESULT.println(resultConstrainingNode + " => " + resultValidatableNode);
}
else {
createResultNodes(validatable, childConstrainingNode);
}
}
}
}
/**
* Creates a ResultSet.
*
* @return the created ResultSet
*/
protected @NonNull ResultSet createResultSet() {
return ValidityFactory.eINSTANCE.createResultSet();
}
/**
* Return a new ResultSet object containing an initial result for every
* enabled combination of ValidatableNode and ConstrainingNode. Returns null
* if the creation process was aborted.
*
* @param monitor
* the corresponding monitor
* @return the ResultSet
*/
public /*synchronized*/ @Nullable ResultSet createResultSet(@Nullable IProgressMonitor monitor) {
ResultSet resultSet = createResultSet();
List<@NonNull Result> results = ClassUtil.nullFree(resultSet.getResults());
if (!createResults(results, ClassUtil.nullFree(rootNode.getValidatableNodes()), monitor)) {
return null;
}
else {
rootNode.getResultSets().add(resultSet);
return resultSet;
}
}
/**
* Creates a ResultValidatableNode
*
* @return the created ResultValidatableNode
*/
protected @NonNull ResultValidatableNode createResultValidatableNode() {
return ValidityFactory.eINSTANCE.createResultValidatableNode();
}
/**
* Created Results of all validatableNodes.
*
* @param results
* the created results
* @param validatableNodes
* the validatableNodes
* @param monitor
* the corresponding monitor
* @return true if the results are created well, false otherwise
*/
protected boolean createResults(@NonNull List<@NonNull Result> results, @NonNull List<@NonNull ? extends ValidatableNode> validatableNodes, @Nullable IProgressMonitor monitor) {
for (int i = 0; i < validatableNodes.size(); i++) { // Avoid CME from domain growth
ValidatableNode validatable = ClassUtil.nonNull(validatableNodes.get(i));
AbstractNode parent = validatable.getParent();
if (validatable.isEnabled() && (parent == null || parent.isEnabled())) {
if (validatable instanceof ResultValidatableNode) {
ResultValidatableNode resultValidatableNode = (ResultValidatableNode) validatable;
ConstrainingNode constraint = resultValidatableNode.getResultConstrainingNode().getParent();
Result result = createResult(monitor);
if (result == null) {
return false;
}
result.setResultValidatableNode(resultValidatableNode);
ResultConstrainingNode resultConstrainingNode = resultValidatableNode.getResultConstrainingNode();
if (!constraint.isEnabled() || !resultConstrainingNode.isEnabled()) {
result.setSeverity(Severity.UNKNOWN);
} else {
results.add(result);
}
}
}
if (!createResults(results, ClassUtil.nullFree(validatable.getChildren()), monitor)) {
return false;
}
}
return true;
}
/**
* @return the created RootConstrainingNode
*/
protected @NonNull RootConstrainingNode createRootConstrainingNode() {
return ValidityFactory.eINSTANCE.createRootConstrainingNode();
}
/**
* @return the created RootValidatableNode
*/
protected @NonNull RootValidatableNode createRootValidatableNode() {
return ValidityFactory.eINSTANCE.createRootValidatableNode();
}
/**
* Create the LeafConstrainingNode parents for each EModelElement that provides constraints
*
* @param allConstraints
* the map from each model element to the LeafConstrainingNode of each of its constraints
*/
protected void createTypeConstrainingNodes(@NonNull Map<@NonNull EObject, @NonNull List<@NonNull LeafConstrainingNode>> allConstraints, @NonNull Monitor monitor) { // FIXME rename
Set<@NonNull ConstrainingNode> allTypeConstrainingNodes = new HashSet<@NonNull ConstrainingNode>();
for (@NonNull EObject constrainingType : allConstraints.keySet()) {
if (monitor.isCanceled()) {
break;
}
buildTypeClosure(constrainingType);
TypeURI typeURI = validityManager.getTypeURI(constrainingType);
List<@NonNull ConstrainingURI> typeURIconstrainingURIs = type2constrainingType.get(typeURI);
if (typeURIconstrainingURIs == null) {
typeURIconstrainingURIs = new ArrayList<@NonNull ConstrainingURI>();
type2constrainingType.put(typeURI, typeURIconstrainingURIs);
}
List<@NonNull LeafConstrainingNode> leafConstrainingNodes = allConstraints.get(constrainingType);
if (leafConstrainingNodes != null) {
for (@NonNull LeafConstrainingNode leafConstrainingNode : leafConstrainingNodes) {
Object constrainingObject = leafConstrainingNode.getConstrainingObject();
if (constrainingObject != null) {
ConstraintLocator constraintLocator = leafConstrainingNode.getConstraintLocator();
EObject constrainingContainer = constraintLocator.getConstrainingType(constrainingType, constrainingObject);
ConstrainingURI constrainingURI = validityManager.getConstrainingURI(constrainingContainer);
if (!typeURIconstrainingURIs.contains(constrainingURI)) {
// System.out.println(typeURI + " is constrained by " + constrainingURI);
typeURIconstrainingURIs.add(constrainingURI);
}
ConstrainingNode typeConstrainingNode = getConstrainingNode(constrainingContainer);
typeConstrainingNode.getChildren().add(leafConstrainingNode);
allTypeConstrainingNodes.add(typeConstrainingNode);
}
}
}
}
}
/**
* @return the created ValidatableNode
*/
protected @NonNull ValidatableNode createValidatableNode() {
return ValidityFactory.eINSTANCE.createValidatableNode();
}
/**
* Returns the eObject label
*
* @param eObject
* @return The eObject label
*/
public @NonNull String getConstrainingLabel(@NonNull EObject eObject) {
return validityManager.getConstrainingLabel(eObject);
}
/**
* Return the ConstrainingNode node for EObject creating any parent
* ConstrainingNodes that are required to ensure that the returned
* ConstrainingNode is installed in the root.
*/
public @NonNull ConstrainingNode getConstrainingNode(@NonNull EObject constrainingObject) {
ConstrainingURI constrainingURI = validityManager.getConstrainingURI(constrainingObject);
ConstrainingNode constrainingNode = allConstrainingNodes.get(constrainingURI);
if (constrainingNode == null) {
EObject eContainer = constrainingObject.eContainer();
if (eContainer == null) {
RootConstrainingNode rootConstrainingNode = createRootConstrainingNode();
rootNode.getConstrainingNodes().add(rootConstrainingNode);
constrainingNode = rootConstrainingNode;
}
else {
constrainingNode = createConstrainingNode();
ConstrainingNode parentConstrainingNode = getConstrainingNode(eContainer);
parentConstrainingNode.getChildren().add(constrainingNode);
}
constrainingNode.setConstrainingObject(constrainingObject);
String label = validityManager.getConstrainingLabel(constrainingObject);
constrainingNode.setLabel(label);
constrainingNode.setEnabled(true);
allConstrainingNodes.put(constrainingURI, constrainingNode);
ValidityManager.CREATE_CONSTRAINING.println(constrainingURI + " => " + constrainingNode);
}
return constrainingNode;
}
protected @NonNull Iterable<@NonNull ConstraintLocator> getConstraintLocators(@NonNull String nsURI) {
return validityManager.getActiveConstraintLocators(nsURI);
}
/**
* @return all resources
*/
public @NonNull Collection<Resource> getResources() {
return resources;
}
public @NonNull String getResultConstrainingLabel(@NonNull ValidatableNode validatableNode) {
StringBuilder s = getResultPath(new StringBuilder(), validatableNode.getParent());
s.append(validatableNode.getLabel());
return s.toString();
}
protected @NonNull StringBuilder getResultPath(@NonNull StringBuilder s, @Nullable AbstractNode abstractNode) {
if (abstractNode != null) {
getResultPath(s, abstractNode.getParent());
// String label = abstractNode.getLabel();
// int index = label.indexOf(' ');
// s.append(index > 0 ? label.substring(0, index) : label);
// s.append(label);
// StringBuilder s = new StringBuilder();
if (abstractNode instanceof ConstrainingNode) {
s.append(ILabelGenerator.Registry.INSTANCE.labelFor(((ConstrainingNode)abstractNode).getConstrainingObject(), ValidityManager.LABEL_OPTIONS));
}
else if (abstractNode instanceof ValidatableNode) {
s.append(ILabelGenerator.Registry.INSTANCE.labelFor(((ValidatableNode)abstractNode).getConstrainedObject(), ValidityManager.LABEL_OPTIONS));
}
s.append("::");
}
return s;
}
public @NonNull String getResultValidatableLabel(@NonNull ConstrainingNode constrainingNode) {
StringBuilder s = getResultPath(new StringBuilder(), constrainingNode.getParent());
s.append(constrainingNode.getLabel());
return s.toString();
}
/**
* @return the root node
*/
public @NonNull RootNode getRootNode() {
return rootNode;
}
/**
* Return the ValidatableNode node for EObject creating any ValidatableNodes
* that are required to ensure that the returned ValidatableNode is
* installed in the root.
*
* @param eObject
* the modelElement
* @return the ValidatableNode node for EObject
*/
protected @NonNull ValidatableNode getValidatableNode(@NonNull EObject eObject) {
ValidatableURI validatableURI = validityManager.getValidatableURI(eObject);
ValidatableNode validatable = allValidatableNodes.get(validatableURI);
if (validatable == null) {
EObject eContainer = eObject.eContainer();
if (eContainer == null && eObject instanceof DynamicEObjectImpl) {
EClass eClass = eObject.eClass();
for (EStructuralFeature eStructuralFeature : eClass.getEAllStructuralFeatures()) {
String featureName = eStructuralFeature.getName();
if ((featureName != null) && featureName.startsWith(DerivedConstants.STEREOTYPE_BASE_PREFIX)
&& (eStructuralFeature instanceof EReference)
&& eObject.eIsSet(eStructuralFeature)) { // Unset for an applicable stereotype that has not been applied
eContainer = (EObject) eObject.eGet(eStructuralFeature);
break;
}
}
}
if (eContainer != null) {
validatable = createValidatableNode();
ValidatableNode parentValidatableNode = getValidatableNode(eContainer);
parentValidatableNode.getChildren().add(validatable);
}
else {
RootValidatableNode rootValidatableNode = createRootValidatableNode();
rootNode.getValidatableNodes().add(rootValidatableNode);
validatable = rootValidatableNode;
}
validatable.setEnabled(true);
validatable.setLabel(validityManager.getValidatableLabel(eObject, eContainer == null));
validatable.setConstrainedObject(eObject);
allValidatableNodes.put(validatableURI, validatable);
ValidityManager.CREATE_VALIDATABLE.println(validatableURI + " => " + validatable);
}
return validatable;
}
/**
* Initialize the ValidityModel
*/
public void init(@NonNull Monitor monitor) {
// long start = System.currentTimeMillis();
// System.out.format(Thread.currentThread().getName() + " %3.3f analyzeResources\n", (System.currentTimeMillis() - start) * 0.001);
Map<@NonNull EPackage, @NonNull Set<@NonNull Resource>> ePackage2resources = analyzeResources(resources, monitor, WORK_FOR_ANALYZE_RESOURCES); // Find all EClasses and EPackages in the source Resources
// System.out.format(Thread.currentThread().getName() + " %3.3f locateConstraints\n", (System.currentTimeMillis() - start) * 0.001);
Map<@NonNull EObject, @NonNull List<@NonNull LeafConstrainingNode>> allConstraints = locateConstraints(ePackage2resources, monitor, WORK_FOR_LOCATE_CONSTRAINTS);
if (monitor.isCanceled()) {
return;
}
if (allConstraints != null) {
// System.out.format(Thread.currentThread().getName() + " %3.3f createLeafConstrainingNodes\n", (System.currentTimeMillis() - start) * 0.001);
createTypeConstrainingNodes(allConstraints, monitor);
}
if (monitor.isCanceled()) {
return;
}
// System.out.format(Thread.currentThread().getName() + " %3.3f createResultNodes\n", (System.currentTimeMillis() - start) * 0.001);
createResultNodes(resources, monitor, WORK_FOR_CREATE_RESULTS);
if (monitor.isCanceled()) {
return;
}
monitor.setTaskName("Sorting Constraints");
// System.out.format(Thread.currentThread().getName() + " %3.3f sort ConstrainingNodes\n", (System.currentTimeMillis() - start) * 0.001);
@SuppressWarnings("null")EList<@NonNull RootConstrainingNode> constrainingNodes = rootNode.getConstrainingNodes();
sortNodes(constrainingNodes, labelComparator);
monitor.worked(WORK_FOR_SORT_CONSTRAINING_NODES);
if (monitor.isCanceled()) {
return;
}
monitor.setTaskName("Sorting Model Elements");
// System.out.format(Thread.currentThread().getName() + " %3.3f sort ValidatableNodes\n", (System.currentTimeMillis() - start) * 0.001);
@SuppressWarnings("null")EList<@NonNull RootValidatableNode> validatableNodes = rootNode.getValidatableNodes();
sortNodes(validatableNodes, natureComparator);
monitor.worked(WORK_FOR_SORT_VALIDATABLE_NODES);
}
/**
* Find all constraints for each EClass
*
* @param ePackage2resources
* the map of all ePackages and their resources
* @return all constraints for each EClass
*/
protected @Nullable Map<@NonNull EObject, @NonNull List<@NonNull LeafConstrainingNode>> locateConstraints(@NonNull Map<@NonNull EPackage, @NonNull Set<@NonNull Resource>> ePackage2resources, @NonNull Monitor monitor, int worked) {
monitor.setTaskName("Locating Constraints");
MonitorStep monitorStep = new MonitorStep(monitor, worked);
try {
Map<@NonNull EObject, @NonNull List<@NonNull LeafConstrainingNode>> allConstraints = new HashMap<@NonNull EObject, @NonNull List<@NonNull LeafConstrainingNode>>();
Set<@NonNull EPackage> ePackages = ePackage2resources.keySet();
int ePackagesCount = ePackages.size();
for (@NonNull EPackage ePackage : ePackages) {
if (monitor.isCanceled()) {
return null;
}
String nsURI = ePackage.getNsURI();
if (nsURI != null) {
monitor.subTask("'" + nsURI + "'");
Iterable<ConstraintLocator> list = getConstraintLocators(nsURI);
if (list != null) {
Set<Resource> ePackageResources = ePackage2resources.get(ePackage);
assert ePackageResources != null;
for (ConstraintLocator constraintLocator : list) {
if (monitor.isCanceled()) {
return null;
}
String subTaskName = "PackageURI \"" + nsURI + "\" - \"" + constraintLocator.getName() + "\"";
monitor.subTask(subTaskName);
ValidityManager.LOCATE_RESOURCE.println(subTaskName);
try {
Map<@NonNull EObject, @NonNull List<@NonNull LeafConstrainingNode>> availableConstraints = constraintLocator.getConstraints(this, ePackage, ePackageResources, monitor);
if (availableConstraints != null) {
assert !availableConstraints.containsKey(null);
for (@NonNull EObject constrainedType : availableConstraints.keySet()) {
List<LeafConstrainingNode> typeConstraints = allConstraints.get(constrainedType);
if (typeConstraints == null) {
typeConstraints = new ArrayList<LeafConstrainingNode>();
allConstraints.put(constrainedType, typeConstraints);
}
int oldSize = typeConstraints.size();
List<@NonNull LeafConstrainingNode> someConstraints = availableConstraints.get(constrainedType);
assert someConstraints != null;
typeConstraints.addAll(someConstraints);
int newSize = typeConstraints.size();
if (newSize > oldSize) {
ValidityManager.LOCATE_RESOURCE.println((newSize-oldSize) + " constraints for ConstrainingURI \"" + validityManager.getConstrainingURI(constrainedType) + "\"");
}
}
}
}
catch (Exception e) {
Set<@NonNull ConstraintLocator> badConstraintLocators2 = badConstraintLocators;
if (badConstraintLocators2 == null) {
synchronized (this) {
badConstraintLocators = badConstraintLocators2 = new HashSet<@NonNull ConstraintLocator>();
}
}
if (!badConstraintLocators2.contains(constraintLocator)) {
synchronized (badConstraintLocators2) {
if (badConstraintLocators2.add(constraintLocator)) {
logger.error("ConstraintLocator " + constraintLocator + " failed", e);
}
}
}
}
}
}
}
monitorStep.workedFraction(ePackagesCount);
}
return allConstraints;
} finally {
monitorStep.done();
}
}
public void refreshModel(@Nullable List<@NonNull AbstractNode> grayedValidatableNodes,
@Nullable List<@NonNull AbstractNode> grayedConstrainingNodes) {
RootNode rootNode = validityManager.getRootNode();
if (rootNode != null) {
// long start = System.currentTimeMillis();
@NonNull List<@NonNull RootValidatableNode> validatableNodes = new ArrayList<@NonNull RootValidatableNode>(ClassUtil.nullFree(rootNode.getValidatableNodes())); // Avoid CME
@NonNull List<@NonNull RootConstrainingNode> constrainingNodes = new ArrayList<@NonNull RootConstrainingNode>(ClassUtil.nullFree(rootNode.getConstrainingNodes())); // Avoid CME
// System.out.format(Thread.currentThread().getName() + " %3.3f revisible ValidatableNodes\n", (System.currentTimeMillis() - start) * 0.001);
for (@NonNull AbstractNode aNode : validatableNodes) {
aNode.refreshVisibleChildren(validatableFilters);
}
// System.out.format(Thread.currentThread().getName() + " %3.3f revisible ConstrainingNodes\n", (System.currentTimeMillis() - start) * 0.001);
for (@NonNull AbstractNode aNode : constrainingNodes) {
aNode.refreshVisibleChildren(constrainingFilters);
}
// System.out.format(Thread.currentThread().getName() + " %3.3f regray ValidatableNodes\n", (System.currentTimeMillis() - start) * 0.001);
for (@NonNull AbstractNode aNode : validatableNodes) {
aNode.refreshGrayed();
}
// System.out.format(Thread.currentThread().getName() + " %3.3f regray ConstrainingNodes\n", (System.currentTimeMillis() - start) * 0.001);
for (@NonNull AbstractNode aNode : constrainingNodes) {
aNode.refreshGrayed();
}
List<@NonNull AbstractNode> grayedValidatableNodes2 = grayedValidatableNodes;
if (grayedValidatableNodes2 != null) {
// System.out.format(Thread.currentThread().getName() + " %3.3f Redraw compute grays\n", (System.currentTimeMillis() - start) * 0.001);
for (@NonNull AbstractNode abstractNode : validatableNodes) {
abstractNode.getGrayedElements(grayedValidatableNodes2);
}
}
List<@NonNull AbstractNode> grayedConstrainingNodes2 = grayedConstrainingNodes;
if (grayedConstrainingNodes2 != null) {
for (@NonNull AbstractNode abstractNode : constrainingNodes) {
abstractNode.getGrayedElements(grayedConstrainingNodes2);
}
}
}
}
public void removeConstrainingFilter(@NonNull IVisibilityFilter filter) {
constrainingFilters.remove(filter);
}
public void removeFilteredSeverity(@NonNull Severity severity) {
if (!constrainingNodesFilterByKind.removeFilteredSeverity(severity)) {
constrainingFilters.remove(constrainingNodesFilterByKind);
}
if (!validatableNodesFilterByKind.removeFilteredSeverity(severity)) {
validatableFilters.remove(validatableNodesFilterByKind);
}
}
public void removeValidatableFilter(@NonNull IVisibilityFilter filter) {
validatableFilters.remove(filter);
}
/**
* Sorts the list.
*
* @param nodes
* the list of nodes needing to be sorted.
*/
protected <@NonNull T extends AbstractNode> void sortEList(@NonNull EList<T> nodes, @NonNull Comparator<@NonNull AbstractNode> comparator) {
List<T> sortedList = new ArrayList<T>(nodes);
Collections.sort(sortedList, comparator);
for (int i = 0; i < sortedList.size(); i++) {
nodes.move(i, sortedList.get(i));
}
}
/**
* Sorts the list.
*
* @param nodes
* the list of nodes needing to be sorted.
*/
protected <@NonNull T extends AbstractNode> void sortNodes(@NonNull EList<T> nodes, @NonNull Comparator<@NonNull AbstractNode> comparator) {
sortEList(nodes, comparator);
for (@NonNull AbstractNode node : nodes) {
sortNodes(ClassUtil.nullFree(node.getChildren()), comparator);
}
}
}