| /******************************************************************************* |
| * Copyright (c) 2014 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.pivot.validation; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.emf.common.util.DiagnosticChain; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EDataType; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EValidator; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| |
| /** |
| * A ComposedEValidator supports validation over a list of EValidators, validation terminating prematurely at |
| * the first child EValidator that returns false. |
| * <p> |
| * A ComposedEValidator may be installed to displace an EValidator.Registry.INSTANCE entry. This in itself is |
| * harmless but since the EValidator.Registry.INSTANCE is global, any additional EValidators added to the |
| * ComposedEValidator should restrict their activities to ResourceSets in which they are required. |
| */ |
| public class ComposedEValidator implements EValidator |
| { |
| private static @Nullable Object getEValidator(@NonNull EValidator.Registry eValidatorRegistry, @NonNull EClass eClass) { |
| List<EClass> eSuperTypes = eClass.getESuperTypes(); |
| EClass eSuperClass = eSuperTypes.size() > 0 ? eSuperTypes.get(0) : null; |
| if (eSuperClass == null) { |
| return eValidatorRegistry.get(null); |
| } |
| Object eValidator = eValidatorRegistry.get(eSuperClass.eContainer()); |
| if (eValidator != null) { |
| return eValidator; |
| } |
| return getEValidator(eValidatorRegistry, eSuperClass); |
| } |
| |
| /** |
| * Install a ComposedEValidator for ePackage displacing the prevailing EValidator.Registry.INSTANCE |
| * entry and adding it as the first ComposedEValidator child. |
| */ |
| public static synchronized @NonNull ComposedEValidator install(@NonNull EPackage ePackage) { |
| Registry eValidatorRegistry = EValidator.Registry.INSTANCE; |
| synchronized (eValidatorRegistry) { |
| Object oldEValidator = eValidatorRegistry.get(ePackage); |
| if (oldEValidator == null) { |
| for (EClassifier eClassifier : ePackage.getEClassifiers()) { |
| if (eClassifier instanceof EClass) { |
| oldEValidator = getEValidator(eValidatorRegistry, (EClass)eClassifier); |
| if (oldEValidator != null) { |
| break; |
| } |
| } |
| } |
| } |
| if (oldEValidator instanceof ComposedEValidator) { |
| return (ComposedEValidator) oldEValidator; |
| } |
| if (oldEValidator instanceof EValidator.Descriptor) { |
| oldEValidator = ((EValidator.Descriptor)oldEValidator).getEValidator(); |
| } |
| ComposedEValidator newEValidator = new ComposedEValidator(oldEValidator instanceof EValidator ? (EValidator) oldEValidator : null); |
| eValidatorRegistry.put(ePackage, newEValidator); |
| return newEValidator; |
| } |
| } |
| |
| protected final @NonNull List<EValidator> eValidators = new ArrayList<EValidator>(); |
| |
| public ComposedEValidator(@Nullable EValidator eValidator) { |
| if (eValidator != null) { |
| eValidators.add(eValidator); |
| } |
| } |
| |
| /** |
| * Add a child EValidator, suppressing null and duplicates. |
| */ |
| public void addChild(@Nullable EValidator eValidator) { |
| if (eValidator != null) { |
| synchronized (this) { |
| if (!eValidators.contains(eValidator)) { |
| eValidators.add(eValidator); |
| } |
| } |
| } |
| } |
| |
| public @NonNull List<EValidator> getChildren() { |
| return eValidators; |
| } |
| |
| public boolean removeChild(@Nullable EValidator eValidator) { |
| return eValidators.remove(eValidator); |
| } |
| |
| @Override |
| public boolean validate(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) { |
| boolean allOk = true; |
| for (EValidator eValidator : eValidators) { |
| if (allOk || (diagnostics != null)) { |
| allOk &= eValidator.validate(eObject, diagnostics, context); |
| } |
| } |
| return allOk; |
| } |
| |
| @Override |
| public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) { |
| boolean allOk = true; |
| for (EValidator eValidator : eValidators) { |
| if (allOk || (diagnostics != null)) { |
| allOk &= eValidator.validate(eClass, eObject, diagnostics, context); |
| } |
| } |
| return allOk; |
| } |
| |
| @Override |
| public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context) { |
| boolean allOk = true; |
| for (EValidator eValidator : eValidators) { |
| if (allOk || (diagnostics != null)) { |
| allOk &= eValidator.validate(eDataType, value, diagnostics, context); |
| } |
| } |
| return allOk; |
| } |
| } |