blob: d271023d31bcd1306f55ad4d0e4b341ca4e6364e [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 - Optimize View Input Refresh
*******************************************************************************/
package org.eclipse.ocl.examples.emf.validation.validity.manager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.BasicMonitor;
import org.eclipse.emf.common.util.Monitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
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.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.RootNode;
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.plugin.ValidityPlugin;
import org.eclipse.ocl.examples.emf.validation.validity.utilities.IVisibilityFilter;
import org.eclipse.ocl.pivot.labels.ILabelGenerator;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.LabelUtil;
import org.eclipse.ocl.pivot.utilities.TracingOption;
import org.eclipse.ocl.pivot.utilities.URIUtil;
public class ValidityManager
{
private static final @NonNull Map<@Nullable String, @NonNull List<ConstraintLocator.@NonNull Descriptor>> constraintLocatorDescriptors = new HashMap<@Nullable String, @NonNull List<ConstraintLocator.@NonNull Descriptor>>();
private static final @NonNull Map<@NonNull String, @NonNull List<@NonNull ConstraintLocator>> constraintLocators = new HashMap<@NonNull String, @NonNull List<@NonNull ConstraintLocator>>();
public static final @NonNull TracingOption ANALYZE_RESOURCE = new TracingOption(ValidityPlugin.PLUGIN_ID, "analyze/resource");
public static final @NonNull TracingOption BUILD_TYPE = new TracingOption(ValidityPlugin.PLUGIN_ID, "build/type");
public static final @NonNull TracingOption CREATE_CONSTRAINING = new TracingOption(ValidityPlugin.PLUGIN_ID, "create/constraining");
public static final @NonNull TracingOption CREATE_RESULT = new TracingOption(ValidityPlugin.PLUGIN_ID, "create/result");
public static final @NonNull TracingOption CREATE_VALIDATABLE = new TracingOption(ValidityPlugin.PLUGIN_ID, "create/validatable");
public static final @NonNull TracingOption LOCATE_RESOURCE = new TracingOption(ValidityPlugin.PLUGIN_ID, "locate/resource");
public static final @NonNull Map<ILabelGenerator.@NonNull Option<?>, @Nullable Object> LABEL_OPTIONS = new HashMap<ILabelGenerator.@NonNull Option<?>, @Nullable Object>();
static {
LABEL_OPTIONS.put(ILabelGenerator.Builder.SHOW_QUALIFIER, null);
}
private final @NonNull LinkedHashSet<@NonNull Resource> newResources = new LinkedHashSet<@NonNull Resource>();
private final @NonNull Set<@NonNull Resource> oldResources = new HashSet<@NonNull Resource>();
/**
* This add the corresponding constraint locator if it exists in the list of
* defined descriptors.
*
* @param nsURI
* the nsURI of the validated resource
* @param constraintLocator
* the corresponding constraint locator
*/
public static synchronized void addConstraintLocator(/*@NonNull*/ String nsURI, ConstraintLocator.@NonNull Descriptor constraintLocator) {
List<ConstraintLocator.@NonNull Descriptor> list = constraintLocatorDescriptors.get(nsURI);
if (list == null) {
list = new ArrayList<ConstraintLocator.@NonNull Descriptor>();
constraintLocatorDescriptors.put(nsURI, list);
}
if (!list.contains(constraintLocator)) {
list.add(constraintLocator);
constraintLocators.remove(nsURI);
}
}
public static synchronized @Nullable ConstraintLocator getConstraintLocator(@NonNull EObject validatableObject) {
return getConstraintLocator(validatableObject.eResource());
}
public static synchronized @Nullable ConstraintLocator getConstraintLocator(@Nullable Resource validatableResource) {
if (validatableResource != null) {
for (@NonNull EObject validatableObject : ClassUtil.nullFree(validatableResource.getContents())) {
EClass eClass = validatableObject.eClass();
if (eClass != null) {
EPackage ePackage = eClass.getEPackage();
if (ePackage != null) {
String nsURI = ePackage.getNsURI();
if (nsURI != null) {
List<@NonNull ConstraintLocator> list = getConstraintLocators(nsURI);
if ((list != null) && (list.size() > 0)) {
return list.get(0);
}
}
}
}
}
}
return null;
}
public static synchronized @NonNull List<@NonNull ConstraintLocator> getConstraintLocators(@NonNull String nsURI) {
List<@NonNull ConstraintLocator> list = constraintLocators.get(nsURI);
if (list == null) {
list = new ArrayList<@NonNull ConstraintLocator>();
constraintLocators.put(nsURI, list);
List<ConstraintLocator.@NonNull Descriptor> descriptors = constraintLocatorDescriptors.get(nsURI);
if (descriptors == null) {
descriptors = constraintLocatorDescriptors.get(null);
}
if (descriptors != null) {
for (ConstraintLocator.@NonNull Descriptor descriptor : descriptors) {
ConstraintLocator constraintLocator = descriptor.getConstraintLocator();
ConstraintLocator constraintLocatorInstance = constraintLocator.getInstance();
if (!list.contains(constraintLocatorInstance)) {
list.add(constraintLocatorInstance);
}
}
}
}
return list;
}
protected final @NonNull ComposedAdapterFactory adapterFactory;
protected final @NonNull Map<@NonNull ResultValidatableNode, @NonNull Result> resultsMap = new HashMap<@NonNull ResultValidatableNode, @NonNull Result>();
protected final @SuppressWarnings("null")@NonNull Map<Object, Object> context = Diagnostician.INSTANCE.createDefaultContext();
private @Nullable ValidityModel model = null;
protected @Nullable ResultSet lastResultSet = null;
private boolean forceRefresh = false;
private @Nullable Object lastInput = null;
public ValidityManager() {
adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
adapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory());
adapterFactory.addAdapterFactory(new EcoreItemProviderAdapterFactory());
adapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());
}
public void addConstrainingFilter(@NonNull IVisibilityFilter filter) {
ValidityModel model2 = model;
if (model2 != null) {
model2.addConstrainingFilter(filter);
}
}
public void addFilteredSeverity(@NonNull Severity severity) {
ValidityModel model2 = model;
if (model2 != null) {
model2.addFilteredSeverity(severity);
}
}
public void addValidatableFilter(@NonNull IVisibilityFilter filter) {
ValidityModel model2 = model;
if (model2 != null) {
model2.addValidatableFilter(filter);
}
}
protected void appendResourceURI(StringBuilder s, EObject eObject) {
EObject eContainer = eObject.eContainer();
if (eContainer == null) {
Resource eResource = eObject.eResource();
if (eResource != null) {
URI uri = eResource.getURI();
if (uri != null) {
ResourceSet resourceSet = eResource.getResourceSet();
if (resourceSet == null) { // Probably a generated package
s.append(" in " + uri);
}
else {
Resource firstResource = resourceSet.getResources().get(0);
URI firstURI = firstResource.getURI();
URI resolvedURI = URIUtil.deresolve(uri, firstURI);
if (resolvedURI.segmentCount() <= 0) {
s.append(" in " + uri.lastSegment());
}
else if (!resolvedURI.toString().equals(s.toString())) { // Skip redundant repetition of name for e.g. CompleteOCLDocumentCS
s.append(" in " + resolvedURI);
}
}
}
}
}
}
public @NonNull Map<Object, Object> createDefaultContext() {
return context;
}
@SuppressWarnings("null")
public @NonNull BasicDiagnostic createDefaultDiagnostic(@NonNull EObject eObject) {
return Diagnostician.INSTANCE.createDefaultDiagnostic(eObject);
}
protected @NonNull ValidityModel createModel(@NonNull Collection<@NonNull Resource> newResources) {
return new ValidityModel(this, newResources);
}
public /*synchronized*/ @Nullable ResultSet createResultSet(@Nullable IProgressMonitor monitor) {
ValidityModel model2 = model;
return model2 != null ? model2.createResultSet(monitor) : null;
}
public void dispose() {
model = null;
lastResultSet = null;
resultsMap.clear();
}
protected @Nullable Set<@NonNull ConstraintLocator> gatherConstraintLocators(@Nullable Set<@NonNull ConstraintLocator> set, @NonNull List<@NonNull ConstraintLocator> list) {
if (set == null) {
set = new HashSet<@NonNull ConstraintLocator>();
}
set.addAll(list);
return set;
}
public @NonNull Iterable<@NonNull ConstraintLocator> getActiveConstraintLocators(@NonNull String nsURI) {
return getConstraintLocators(nsURI);
}
public @NonNull AdapterFactory getAdapterFactory() {
return adapterFactory;
}
/**
* Return the ConstrainingNode node for EObject creating any ConstrainingNodes that
* are required to ensure that the returned ConstrainingNode is installed in the root.
*/
public @NonNull ConstrainingNode getConstrainingNode(@NonNull EObject eObject) {
ValidityModel model2 = model;
if (model2 == null) {
throw new IllegalStateException();
}
return model2.getConstrainingNode(eObject);
}
public @NonNull List<@NonNull Result> getConstrainingNodeResults(@NonNull ConstrainingNode element) {
List<@NonNull Result> results = new ArrayList<@NonNull Result>();
if (element.getLabel().startsWith("EOperation")) {
getAllConstrainingNodeResults(results, element);
}
else {
getAllConstrainingNodeResults(results, element);
}
return results;
}
/**
* Returns the eObject uri
*
* @param eObject
* @return the eObject uri
*/
public @NonNull ConstrainingURI getConstrainingURI(@NonNull EObject eObject) {
ConstraintLocator constraintLocator = ValidityManager.getConstraintLocator(eObject);
if (constraintLocator != null) {
ConstrainingURI uri = constraintLocator.getConstrainingURI(eObject);
if (uri != null) {
return uri;
}
}
@NonNull URI uri = EcoreUtil.getURI(eObject);
return new ConstrainingURI(uri);
}
private void getAllConstrainingNodeResults(@NonNull List<@NonNull Result> results, @NonNull ConstrainingNode element) {
if (element instanceof ResultConstrainingNode) {
ResultValidatableNode resultValidatableNode = ((ResultConstrainingNode)element).getResultValidatableNode();
Result result = resultsMap.get(resultValidatableNode);
if (result != null) {
results.add(result);
}
}
else {
for (@NonNull ConstrainingNode child : ClassUtil.nullFree(element.getChildren())) {
getAllConstrainingNodeResults(results, child);
}
}
}
private void getAllValidatableNodeResults(@NonNull List<@NonNull Result> results, @NonNull ValidatableNode element) {
if (element instanceof ResultValidatableNode) {
ResultValidatableNode resultValidatableNode = (ResultValidatableNode)element;
Result result = resultsMap.get(resultValidatableNode);
if (result != null) {
results.add(result);
}
}
else {
for (@NonNull ValidatableNode child : ClassUtil.nullFree(element.getChildren())) {
getAllValidatableNodeResults(results, child);
}
}
}
public @NonNull String getConstrainingLabel(@NonNull EObject eObject) {
StringBuilder s = new StringBuilder();
s.append(ILabelGenerator.Registry.INSTANCE.labelFor(eObject, LABEL_OPTIONS));
appendResourceURI(s, eObject);
return s.toString();
}
public @Nullable ValidityModel getModel() {
return model;
}
public @Nullable RootNode getRootNode() {
ValidityModel model2 = model;
return model2 != null ? model2.getRootNode() : null;
}
/**
* Returns the eObject uri
*/
public @NonNull TypeURI getTypeURI(@NonNull EObject constrainingObject) {
for (EObject eContainer = constrainingObject; eContainer != null; eContainer = eContainer.eContainer()) {
if (eContainer instanceof EPackage) {
EPackage constrainingEPackage = (EPackage) eContainer;
String nsURI = constrainingEPackage.getNsURI();
if ((nsURI != null) && !"".equals(nsURI)) {
Resource eResource = constrainingEPackage.eResource();
if (eResource != null) {
String fragment = eResource.getURIFragment(constrainingObject);
URI uri = URI.createURI(nsURI).appendFragment(fragment);
return new TypeURI(uri);
}
}
}
}
EClass eClass = constrainingObject.eClass();
if (eClass != null) {
EPackage ePackage = eClass.getEPackage();
if (ePackage != null) {
String nsURI = ePackage.getNsURI();
if (nsURI != null) {
List<@NonNull ConstraintLocator> constraintLocators = getConstraintLocators(nsURI);
if (constraintLocators != null) {
for (@NonNull ConstraintLocator constraintLocator : constraintLocators) {
TypeURI uri = constraintLocator.getTypeURI(constrainingObject);
if (uri != null) {
return uri;
}
}
}
}
}
}
@NonNull URI uri = EcoreUtil.getURI(constrainingObject);
return new TypeURI(uri);
}
public @NonNull String getValidatableLabel(@NonNull EObject eObject, boolean withContext) {
StringBuilder s = new StringBuilder();
s.append(LabelUtil.SIMPLE_NAME_REGISTRY.labelFor(eObject, LABEL_OPTIONS));
/* if (eObject instanceof ENamedElement) {
s.append(((ENamedElement)eObject).getName());
}
else {
IItemLabelProvider itemLabelProvider = (IItemLabelProvider)adapterFactory.adapt(eObject, IItemLabelProvider.class);
String label = itemLabelProvider != null ? itemLabelProvider.getText(eObject) : eObject.toString();
s.append(label != null ? label : "");
}
if (eObject instanceof ETypedElement) {
EClassifier eType = ((ETypedElement)eObject).getEType();
s.append(" : " + eType.getName());
}
else {
EClass eClass = eObject.eClass();
if (eClass != null) {
s.append(" | " + eClass.getName());
}
} */
if (withContext) {
appendResourceURI(s, eObject);
}
return s.toString();
}
public @NonNull List<@NonNull Result> getValidatableNodeResults(@NonNull ValidatableNode element) {
List<@NonNull Result> results = new ArrayList<@NonNull Result>();
getAllValidatableNodeResults(results, element);
return results;
}
/**
* Returns the eObject uri
*
* @param eObject
* @return the eObject uri
*/
public @NonNull ValidatableURI getValidatableURI(@NonNull EObject eObject) {
@NonNull URI uri = EcoreUtil.getURI(eObject);
return new ValidatableURI(uri);
}
public void forceRefresh() {
this.forceRefresh = true;
setInput(lastInput, new BasicMonitor());
this.forceRefresh = false;
}
/* public void refreshModel(List<AbstractNode> grayedValidatableNodes,
List<AbstractNode> grayedConstrainingNodes) {
model.refreshModel(grayedValidatableNodes, grayedConstrainingNodes);
RootNode rootNode = validityModel.getRootNode();
if (rootNode != null) {
// System.out.format(Thread.currentThread().getName() + " %3.3f Redraw compute grays\n", (System.currentTimeMillis() - start) * 0.001);
for (AbstractNode abstractNode : rootNode.getConstrainingNodes()) {
abstractNode.getGrayedElements(grayedConstrainingNodes);
}
for (AbstractNode abstractNode : rootNode.getValidatableNodes()) {
abstractNode.getGrayedElements(grayedValidatableNodes);
}
}
// System.out.format(Thread.currentThread().getName() + " %3.3f Redraw schedule main\n", (System.currentTimeMillis() - start) * 0.001);
} */
protected @Nullable List<@NonNull Result> installResultSet(@NonNull ResultSet resultSet, @NonNull IProgressMonitor monitor) {
lastResultSet = resultSet;
resultsMap.clear();
RootNode rootNode = getRootNode();
if (rootNode == null) {
return null;
}
resetResults(ClassUtil.nullFree(rootNode.getValidatableNodes()));
resetResults(ClassUtil.nullFree(rootNode.getConstrainingNodes()));
List<@NonNull Result> results = ClassUtil.nullFree(resultSet.getResults());
for (@NonNull Result result : results) {
ResultValidatableNode resultValidatableNode = result.getResultValidatableNode();
assert resultValidatableNode != null;
resultsMap.put(resultValidatableNode, result);
if (monitor.isCanceled()) {
return null;
}
}
return results;
}
public void removeConstrainingFilter(@NonNull IVisibilityFilter filter) {
ValidityModel model2 = model;
if (model2 != null) {
model2.removeConstrainingFilter(filter);
}
}
public void removeFilteredSeverity(@NonNull Severity severity) {
ValidityModel model2 = model;
if (model2 != null) {
model2.removeFilteredSeverity(severity);
}
}
public void removeValidatableFilter(@NonNull IVisibilityFilter filter) {
ValidityModel model2 = model;
if (model2 != null) {
model2.removeValidatableFilter(filter);
}
}
private void resetResults(@NonNull List<@NonNull ? extends AbstractNode> nodes) {
for (@NonNull AbstractNode node : new ArrayList<>(nodes)) {
resetResults(ClassUtil.nullFree(node.getChildren()));
node.setWorstResult(null);
}
}
public void setInput(Object newInput) {
setInput(newInput, new BasicMonitor());
}
public void setInput(Object newInput, @NonNull Monitor monitor) {
monitor.beginTask("Selective Validation", ValidityModel.WORK_FOR_ALL_SET_INPUT);
monitor.setTaskName("Clean Up");
ResourceSet selectedResourceSet = null;
Resource selectedResource = null;
EObject selectedObject = null;
newResources.clear();
lastInput = newInput;
if (newInput == null) {
oldResources.clear();
model = null;
return;
}
if (newInput instanceof ResourceSet) {
selectedResourceSet = (ResourceSet) newInput;
} else if (newInput instanceof Resource) {
selectedResource = (Resource) newInput;
selectedResourceSet = selectedResource.getResourceSet();
if (selectedResourceSet == null) {
List<@NonNull EObject> eContents = ClassUtil.nullFree(selectedResource.getContents());
for (int j = 0; j < eContents.size(); j++) { // Tolerate domain growth without a CME
EObject eObject = ClassUtil.nonNull(eContents.get(j));
EcoreUtil.resolveAll(eObject);
}
newResources.add(selectedResource);
}
} else if (newInput instanceof EObject) {
selectedObject = (EObject) newInput;
selectedResource = selectedObject.eResource();
if (selectedResource != null) {
selectedResourceSet = selectedResource.getResourceSet();
}
}
if (selectedResourceSet != null) {
synchronized (selectedResourceSet) {
List<@NonNull Resource> selectedResources = ClassUtil.nullFree(selectedResourceSet.getResources());
for (int i = 0; i < selectedResources.size(); i++) { // Tolerate domain growth without a CME
Resource eResource = ClassUtil.nonNull(selectedResources.get(i));
List<EObject> eContents = eResource.getContents();
for (int j = 0; j < eContents.size(); j++) { // Tolerate domain growth without a CME
EObject eObject = eContents.get(j);
EcoreUtil.resolveAll(eObject);
}
}
newResources.addAll(ClassUtil.nullFree(selectedResourceSet.getResources()));
}
}
if (newResources.isEmpty()) {
return;
}
if (!forceRefresh && !oldResources.isEmpty() && oldResources.equals(newResources)) {
return;
}
monitor.worked(ValidityModel.WORK_FOR_CLEAN_UP);
monitor.setTaskName("Creating model");
ValidityModel model2 = model = createModel(newResources);
monitor.worked(ValidityModel.WORK_FOR_CREATE_MODEL);
model2.init(monitor);
oldResources.clear();
if (!monitor.isCanceled()) {
oldResources.addAll(newResources);
}
}
}