| /** |
| * Copyright (c) 2004-2009 IBM Corporation 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: |
| * IBM - Initial API and implementation |
| */ |
| package org.eclipse.emf.ecore.util; |
| |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| |
| import java.lang.reflect.Array; |
| import java.math.BigDecimal; |
| |
| import org.eclipse.emf.common.util.BasicDiagnostic; |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.emf.common.util.DiagnosticChain; |
| import org.eclipse.emf.common.util.EMap; |
| import org.eclipse.emf.common.util.ResourceLocator; |
| |
| import org.eclipse.emf.ecore.EAttribute; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EDataType; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EOperation; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.EValidator; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.InternalEObject; |
| |
| import org.eclipse.emf.ecore.plugin.EcorePlugin; |
| |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| |
| import org.eclipse.emf.ecore.xml.type.XMLTypePackage; |
| import org.eclipse.emf.ecore.xml.type.util.XMLTypeUtil; |
| |
| |
| /** |
| * A validity checker for basic EObject constraints. |
| */ |
| public class EObjectValidator implements EValidator |
| { |
| public static final EObjectValidator INSTANCE = new EObjectValidator(); |
| |
| public static final String DIAGNOSTIC_SOURCE = "org.eclipse.emf.ecore"; |
| |
| public static final int EOBJECT__EVERY_MULTIPCITY_CONFORMS = 1; |
| public static final int EOBJECT__EVERY_DATA_VALUE_CONFORMS = 2; |
| public static final int EOBJECT__EVERY_REFERENCE_IS_CONTAINED = 3; |
| public static final int EOBJECT__EVERY_PROXY_RESOLVES = 4; |
| public static final int DATA_VALUE__VALUE_IN_RANGE = 5; |
| public static final int DATA_VALUE__LENGTH_IN_RANGE = 6; |
| public static final int DATA_VALUE__TYPE_CORRECT = 7; |
| public static final int DATA_VALUE__VALUE_IN_ENUMERATION = 8; |
| public static final int DATA_VALUE__MATCHES_PATTERN = 9; |
| public static final int DATA_VALUE__TOTAL_DIGITS_IN_RANGE = 10; |
| public static final int DATA_VALUE__FRACTION_DIGITS_IN_RANGE = 11; |
| public static final int EOBJECT__UNIQUE_ID = 12; |
| public static final int EOBJECT__EVERY_KEY_UNIQUE = 13; |
| public static final int EOBJECT__EVERY_MAP_ENTRY_UNIQUE = 14; |
| public static final int EOBJECT__NO_CIRCULAR_CONTAINMENT = 15; |
| public static final int EOBJECT__EVERY_BIDIRECTIONAL_REFERENCE_IS_PAIRED = 16; |
| |
| static final int EOBJECT_DIAGNOSTIC_CODE_COUNT = EOBJECT__EVERY_BIDIRECTIONAL_REFERENCE_IS_PAIRED; |
| |
| /** |
| * A key to be used in <code>context</code> maps to indicate the root object at which validation started. |
| * It's used to detect {@link #EOBJECT__NO_CIRCULAR_CONTAINMENT circular containment} |
| * and to prevent {@link Diagnostician#validate(EClass, EObject, DiagnosticChain, Map) infinite recursion}. |
| * The value of the entry must be the root {@link EObject}. |
| * @see EValidator#validate(EObject, DiagnosticChain, Map) |
| * @see #validate_NoCircularContainment(EObject, DiagnosticChain, Map) |
| * @since 2.5 |
| */ |
| public static final String ROOT_OBJECT = "org.eclipse.emf.ecore.EObject_NoCircularContainment"; |
| |
| /** |
| * @since 2.1.0 |
| */ |
| public static String getObjectLabel(EObject eObject, Map<Object, Object> context) |
| { |
| if (context != null) |
| { |
| SubstitutionLabelProvider substitutionlabelProvider = (SubstitutionLabelProvider)context.get(SubstitutionLabelProvider.class); |
| if (substitutionlabelProvider != null) |
| { |
| return substitutionlabelProvider.getObjectLabel(eObject); |
| } |
| } |
| return EcoreUtil.getIdentification(eObject); |
| } |
| |
| /** |
| * @since 2.1.0 |
| */ |
| public static String getFeatureLabel(EStructuralFeature eStructuralFeature, Map<Object, Object> context) |
| { |
| if (context != null) |
| { |
| SubstitutionLabelProvider substitutionlabelProvider = (SubstitutionLabelProvider)context.get(SubstitutionLabelProvider.class); |
| if (substitutionlabelProvider != null) |
| { |
| return substitutionlabelProvider.getFeatureLabel(eStructuralFeature); |
| } |
| } |
| return eStructuralFeature.getName(); |
| } |
| |
| /** |
| * @since 2.1.0 |
| */ |
| public static String getValueLabel(EDataType eDataType, Object value, Map<Object, Object> context) |
| { |
| if (context != null) |
| { |
| SubstitutionLabelProvider substitutionlabelProvider = (SubstitutionLabelProvider)context.get(SubstitutionLabelProvider.class); |
| if (substitutionlabelProvider != null) |
| { |
| return substitutionlabelProvider.getValueLabel(eDataType, value); |
| } |
| } |
| return EcoreUtil.convertToString(eDataType, value); |
| } |
| |
| public EObjectValidator() |
| { |
| super(); |
| } |
| |
| protected EPackage getEPackage() |
| { |
| return EcorePackage.eINSTANCE; |
| } |
| |
| protected EValidator getRootEValidator(Map<Object, Object> context) |
| { |
| if (context != null) |
| { |
| EValidator result = (EValidator)context.get(EValidator.class); |
| if (result != null) |
| { |
| return result; |
| } |
| } |
| |
| return Diagnostician.INSTANCE; |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected static EValidator.ValidationDelegate.Registry getValidationDelegateRegistry(Map<Object, Object> context) |
| { |
| if (context != null) |
| { |
| EValidator.ValidationDelegate.Registry result = (EValidator.ValidationDelegate.Registry)context.get(EValidator.ValidationDelegate.Registry.class); |
| if (result != null) |
| { |
| return result; |
| } |
| } |
| |
| return EValidator.ValidationDelegate.Registry.INSTANCE; |
| } |
| |
| /** |
| * Delegates evaluation of the given invariant expression against the object in the given context. |
| * @return the result of the expression evaluation. |
| * @since 2.6 |
| */ |
| public static boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context, String validationDelegate, EOperation invariant, String expression, int severity, String source, int code) |
| { |
| ValidationDelegate delegate = getValidationDelegateRegistry(context).getValidationDelegate(validationDelegate); |
| if (delegate != null) |
| { |
| try |
| { |
| if (!delegate.validate(eClass, eObject, context, invariant, expression)) |
| { |
| if (diagnostics != null) |
| reportInvariantDelegateViolation(eClass, eObject, diagnostics, context, invariant, severity, source, code); |
| return false; |
| } |
| } |
| catch (Throwable throwable) |
| { |
| if (diagnostics != null) |
| reportInvariantDelegateException(eClass, eObject, diagnostics, context, invariant, severity, source, code, throwable); |
| } |
| } |
| else |
| { |
| if (diagnostics != null) |
| reportInvariantDelegateNotFound(eClass, eObject, diagnostics, context, invariant, severity, source, code, validationDelegate); |
| } |
| return true; |
| } |
| |
| /** |
| * Delegates evaluation of the given constraint expression against the object in the given context. |
| * @return the result of the expression evaluation. |
| * @since 2.6 |
| */ |
| public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context, String validationDelegate, String constraint, String expression, int severity, String source, int code) |
| { |
| ValidationDelegate delegate = getValidationDelegateRegistry(context).getValidationDelegate(validationDelegate); |
| if (delegate != null) |
| { |
| try |
| { |
| if (!delegate.validate(eClass, eObject, context, constraint, expression)) |
| { |
| if (diagnostics != null) |
| reportConstraintDelegateViolation(eClass, eObject, diagnostics, context, constraint, severity, source, code); |
| return false; |
| } |
| } |
| catch (Throwable throwable) |
| { |
| if (diagnostics != null) |
| reportConstraintDelegateException(eClass, eObject, diagnostics, context, constraint, severity, source, code, throwable); |
| } |
| } |
| else |
| { |
| if (diagnostics != null) |
| reportConstraintDelegateNotFound(eClass, eObject, diagnostics, context, constraint, severity, source, code, validationDelegate); |
| } |
| return true; |
| } |
| |
| /** |
| * Delegates evaluation of the given constraint expression against the value in the given context. |
| * @return the result of the expression evaluation. |
| * @since 2.6 |
| */ |
| public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context, String validationDelegate, String constraint, String expression, int severity, String source, int code) |
| { |
| ValidationDelegate delegate = getValidationDelegateRegistry(context).getValidationDelegate(validationDelegate); |
| if (delegate != null) |
| { |
| try |
| { |
| if (!delegate.validate(eDataType, value, context, constraint, expression)) |
| { |
| if (diagnostics != null) |
| reportConstraintDelegateViolation(eDataType, value, diagnostics, context, constraint, severity, source, code); |
| return false; |
| } |
| } |
| catch (Throwable throwable) |
| { |
| if (diagnostics != null) |
| reportConstraintDelegateException(eDataType, value, diagnostics, context, constraint, severity, source, code, throwable); |
| } |
| } |
| else |
| { |
| if (diagnostics != null) |
| reportConstraintDelegateNotFound(eDataType, value, diagnostics, context, constraint, severity, source, code, validationDelegate); |
| } |
| return true; |
| } |
| |
| /** |
| * Validates the object in the given context, optionally producing diagnostics. |
| * @param diagnostics a place to accumulate diagnostics; if it's <code>null</code>, no diagnostics should be produced. |
| * @param context a place to cache information, if it's <code>null</code>, no cache is supported. |
| * @return whether the object is valid. |
| */ |
| public boolean validate(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| return validate(eObject.eClass(), eObject, diagnostics, context); |
| } |
| |
| public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| if (eObject.eIsProxy()) |
| { |
| if (context != null && context.get(ROOT_OBJECT) != null) |
| { |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_PROXY_RESOLVES, |
| "_UI_UnresolvedProxy_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eObject.eContainmentFeature(), context), |
| getObjectLabel(eObject.eContainer(), context), |
| getObjectLabel(eObject, context) |
| }, |
| new Object [] { eObject.eContainer(), eObject.eContainmentFeature(), eObject }, |
| context)); |
| } |
| return false; |
| } |
| else |
| { |
| return true; |
| } |
| } |
| else if (eClass.eContainer() == getEPackage()) |
| { |
| return validate(eClass.getClassifierID(), eObject, diagnostics, context); |
| } |
| else |
| { |
| return |
| new DynamicEClassValidator() |
| { |
| // Ensure that the class loader for this class will be used downstream. |
| // |
| }.validate(eClass, eObject, diagnostics, context); |
| } |
| } |
| |
| protected boolean validate(int classifierID, Object object, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| return classifierID != EcorePackage.EOBJECT || validate_EveryDefaultConstraint((EObject)object, diagnostics, context); |
| } |
| |
| public boolean validate_EveryDefaultConstraint(EObject object, DiagnosticChain theDiagnostics, Map<Object, Object> context) |
| { |
| if (!validate_NoCircularContainment(object, theDiagnostics, context)) |
| { |
| return false; |
| } |
| boolean result = validate_EveryMultiplicityConforms(object, theDiagnostics, context); |
| if (result || theDiagnostics != null) |
| { |
| result &= validate_EveryProxyResolves(object, theDiagnostics, context); |
| } |
| if (result || theDiagnostics != null) |
| { |
| result &= validate_EveryReferenceIsContained(object, theDiagnostics, context); |
| } |
| if (result || theDiagnostics != null) |
| { |
| result &= validate_EveryBidirectionalReferenceIsPaired(object, theDiagnostics, context); |
| } |
| if (result || theDiagnostics != null) |
| { |
| result &= validate_EveryDataValueConforms(object, theDiagnostics, context); |
| } |
| if (result || theDiagnostics != null) |
| { |
| result &= validate_UniqueID(object, theDiagnostics, context); |
| } |
| if (result || theDiagnostics != null) |
| { |
| result &= validate_EveryKeyUnique(object, theDiagnostics, context); |
| } |
| if (result || theDiagnostics != null) |
| { |
| result &= validate_EveryMapEntryUnique(object, theDiagnostics, context); |
| } |
| return result; |
| } |
| |
| public boolean validate_NoCircularContainment(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| if (context != null) |
| { |
| Object root = context.get(ROOT_OBJECT); |
| if (root == null) |
| { |
| context.put(ROOT_OBJECT, eObject); |
| } |
| else if (root == eObject) |
| { |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__NO_CIRCULAR_CONTAINMENT, |
| "_UI_CircularContainment_diagnostic", |
| new Object [] |
| { |
| getObjectLabel(eObject, context), |
| }, |
| new Object [] { eObject }, |
| context)); |
| } |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public boolean validate_EveryBidirectionalReferenceIsPaired(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| for (EReference eReference : eObject.eClass().getEAllReferences()) |
| { |
| if (eReference.isResolveProxies()) |
| { |
| EReference eOpposite = eReference.getEOpposite(); |
| if (eOpposite != null) |
| { |
| result &= validate_BidirectionalReferenceIsPaired(eObject, eReference, eOpposite, diagnostics, context); |
| if (!result && diagnostics == null) |
| { |
| return false; |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| public boolean validate_BidirectionalReferenceIsPaired(EObject eObject, EReference eReference, EReference eOpposite, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| Object value = eObject.eGet(eReference); |
| if (eReference.isMany()) |
| { |
| @SuppressWarnings("unchecked") |
| List<EObject> values = (List<EObject>)value; |
| if (eOpposite.isMany()) |
| { |
| for (EObject oppositeEObject : values) |
| { |
| @SuppressWarnings("unchecked") |
| List<EObject> oppositeValues = (List<EObject>)oppositeEObject.eGet(eOpposite); |
| if (!oppositeValues.contains(eObject)) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| // TODO |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_BIDIRECTIONAL_REFERENCE_IS_PAIRED, |
| "_UI_UnpairedBidirectionalReference_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eReference, context), |
| getObjectLabel(eObject, context), |
| getFeatureLabel(eOpposite, context), |
| getObjectLabel(oppositeEObject, context), |
| }, |
| new Object [] { eObject, eReference, oppositeEObject, eOpposite }, |
| context)); |
| } |
| else |
| { |
| break; |
| } |
| } |
| } |
| } |
| else |
| { |
| for (EObject oppositeEObject : values) |
| { |
| if (oppositeEObject.eGet(eOpposite) != eObject) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| // TODO |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_BIDIRECTIONAL_REFERENCE_IS_PAIRED, |
| "_UI_UnpairedBidirectionalReference_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eReference, context), |
| getObjectLabel(eObject, context), |
| getFeatureLabel(eOpposite, context), |
| getObjectLabel(oppositeEObject, context), |
| }, |
| new Object [] { eObject, eReference, oppositeEObject, eOpposite }, |
| context)); |
| } |
| else |
| { |
| break; |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| EObject oppositeEObject = (EObject)value; |
| if (oppositeEObject != null) |
| { |
| if (eOpposite.isMany()) |
| { |
| @SuppressWarnings("unchecked") |
| List<EObject> oppositeValues = (List<EObject>)oppositeEObject.eGet(eOpposite); |
| if (!oppositeValues.contains(eObject)) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| // TODO |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_BIDIRECTIONAL_REFERENCE_IS_PAIRED, |
| "_UI_UnpairedBidirectionalReference_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eReference, context), |
| getObjectLabel(eObject, context), |
| getFeatureLabel(eOpposite, context), |
| getObjectLabel(oppositeEObject, context), |
| }, |
| new Object [] { eObject, eReference, oppositeEObject, eOpposite }, |
| context)); |
| } |
| } |
| } |
| else |
| { |
| if (oppositeEObject.eGet(eOpposite) != eObject) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_BIDIRECTIONAL_REFERENCE_IS_PAIRED, |
| "_UI_UnpairedBidirectionalReference_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eReference, context), |
| getObjectLabel(eObject, context), |
| getFeatureLabel(eOpposite, context), |
| getObjectLabel(oppositeEObject, context), |
| }, |
| new Object [] { eObject, eReference, oppositeEObject, eOpposite }, |
| context)); |
| } |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| public boolean validate_EveryMultiplicityConforms(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| EClass eClass = eObject.eClass(); |
| for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i) |
| { |
| result &= validate_MultiplicityConforms(eObject, eClass.getEStructuralFeature(i), diagnostics, context); |
| if (!result && diagnostics == null) |
| { |
| return false; |
| } |
| } |
| return result; |
| } |
| |
| protected boolean validate_MultiplicityConforms |
| (EObject eObject, EStructuralFeature eStructuralFeature, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| if (eStructuralFeature.isMany()) |
| { |
| if (FeatureMapUtil.isFeatureMap(eStructuralFeature) && ExtendedMetaData.INSTANCE.isDocumentRoot(eObject.eClass())) |
| { |
| FeatureMap featureMap = (FeatureMap)eObject.eGet(eStructuralFeature); |
| int count = 0; |
| for (int i = 0, size = featureMap.size(); i < size; ++i) |
| { |
| EStructuralFeature feature = featureMap.getEStructuralFeature(i); |
| int kind = ExtendedMetaData.INSTANCE.getFeatureKind(feature); |
| if (kind == ExtendedMetaData.ELEMENT_FEATURE && |
| feature != XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__CDATA && |
| feature != XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__COMMENT && |
| feature != XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__TEXT && |
| feature != XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__PROCESSING_INSTRUCTION && |
| ++count > 1) |
| { |
| result = false; |
| break; |
| } |
| } |
| if (count != 1) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_MULTIPCITY_CONFORMS, |
| "_UI_DocumentRootMustHaveOneElement_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eStructuralFeature, context), |
| getObjectLabel(eObject, context), |
| count |
| }, |
| new Object [] { eObject, eStructuralFeature }, |
| context)); |
| } |
| } |
| } |
| else |
| { |
| int lowerBound = eStructuralFeature.getLowerBound(); |
| if (lowerBound > 0) |
| { |
| int size = ((List<?>)eObject.eGet(eStructuralFeature)).size(); |
| if (size < lowerBound) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_MULTIPCITY_CONFORMS, |
| "_UI_FeatureHasTooFewValues_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eStructuralFeature, context), |
| getObjectLabel(eObject, context), |
| size, |
| lowerBound |
| }, |
| new Object [] { eObject, eStructuralFeature }, |
| context)); |
| } |
| } |
| int upperBound = eStructuralFeature.getUpperBound(); |
| if (upperBound > 0 && size > upperBound) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_MULTIPCITY_CONFORMS, |
| "_UI_FeatureHasTooManyValues_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eStructuralFeature, context), |
| getObjectLabel(eObject, context), |
| size, |
| upperBound |
| }, |
| new Object [] { eObject, eStructuralFeature }, |
| context)); |
| } |
| } |
| } |
| else |
| { |
| int upperBound = eStructuralFeature.getUpperBound(); |
| if (upperBound > 0) |
| { |
| int size = ((List<?>)eObject.eGet(eStructuralFeature)).size(); |
| if (size > upperBound) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_MULTIPCITY_CONFORMS, |
| "_UI_FeatureHasTooManyValues_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eStructuralFeature, context), |
| getObjectLabel(eObject, context), |
| size, |
| upperBound |
| }, |
| new Object [] { eObject, eStructuralFeature }, |
| context)); |
| } |
| } |
| } |
| } |
| } |
| } |
| else if (eStructuralFeature.isRequired()) |
| { |
| if (eStructuralFeature.isUnsettable() ? !eObject.eIsSet(eStructuralFeature) : eObject.eGet(eStructuralFeature, false) == null) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_MULTIPCITY_CONFORMS, |
| "_UI_RequiredFeatureMustBeSet_diagnostic", |
| new Object [] { getFeatureLabel(eStructuralFeature, context), getObjectLabel(eObject, context) }, |
| new Object [] { eObject, eStructuralFeature }, |
| context)); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| public boolean validate_EveryProxyResolves(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| for (EContentsEList.FeatureIterator<EObject> i = (EContentsEList.FeatureIterator<EObject>)eObject.eCrossReferences().iterator(); i.hasNext(); ) |
| { |
| EObject eCrossReferenceObject = i.next(); |
| if (eCrossReferenceObject.eIsProxy()) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_PROXY_RESOLVES, |
| "_UI_UnresolvedProxy_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(i.feature(), context), |
| getObjectLabel(eObject, context), |
| getObjectLabel(eCrossReferenceObject, context) |
| }, |
| new Object [] { eObject, i.feature(), eCrossReferenceObject }, |
| context)); |
| } |
| else |
| { |
| break; |
| } |
| } |
| } |
| return result; |
| } |
| |
| public boolean validate_EveryReferenceIsContained(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| if (eObject.eResource() != null) |
| { |
| for (EContentsEList.FeatureIterator<EObject> i = (EContentsEList.FeatureIterator<EObject>)eObject.eCrossReferences().iterator(); i.hasNext(); ) |
| { |
| EObject eCrossReferenceObject = i.next(); |
| if (eCrossReferenceObject.eResource() == null && !eCrossReferenceObject.eIsProxy() && !i.feature().isTransient()) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_REFERENCE_IS_CONTAINED, |
| "_UI_DanglingReference_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(i.feature(), context), |
| getObjectLabel(eObject, context), |
| getObjectLabel(eCrossReferenceObject, context) |
| }, |
| new Object [] { eObject, i.feature(), eCrossReferenceObject }, |
| context)); |
| } |
| else |
| { |
| break; |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| public boolean validate_EveryDataValueConforms(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| for (EAttribute eAttribute : eObject.eClass().getEAllAttributes()) |
| { |
| result &= validate_DataValueConforms(eObject, eAttribute, diagnostics, context); |
| if (!result && diagnostics == null) |
| { |
| return false; |
| } |
| } |
| return result; |
| } |
| |
| protected boolean validate_DataValueConforms |
| (EObject eObject, EAttribute eAttribute, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| if (!eObject.eIsSet(eAttribute)) |
| { |
| return true; |
| } |
| boolean result = true; |
| EDataType eDataType = eAttribute.getEAttributeType(); |
| EValidator rootValidator = getRootEValidator(context); |
| Object value = eObject.eGet(eAttribute); |
| if (FeatureMapUtil.isFeatureMap(eAttribute)) |
| { |
| @SuppressWarnings("unchecked") Collection<FeatureMap.Entry> featureMap = (Collection<FeatureMap.Entry>)value; |
| EClass eClass = eObject.eClass(); |
| Map<EStructuralFeature, DiagnosticChain> entryFeatureToDiagnosticChainMap = null; |
| for (Iterator<FeatureMap.Entry> i = featureMap.iterator(); i.hasNext() && (result || diagnostics != null); ) |
| { |
| FeatureMap.Entry entry = i.next(); |
| EStructuralFeature entryFeature = entry.getEStructuralFeature(); |
| if (entryFeature instanceof EAttribute && |
| ExtendedMetaData.INSTANCE.getAffiliation(eClass, entryFeature) == eAttribute) |
| { |
| EDataType entryType = (EDataType)entryFeature.getEType(); |
| Object entryValue = entry.getValue(); |
| boolean entryIsValid = rootValidator.validate(entryType, entryValue, null, context); |
| if (!entryIsValid) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| if (entryFeatureToDiagnosticChainMap == null) |
| { |
| entryFeatureToDiagnosticChainMap = new HashMap<EStructuralFeature, DiagnosticChain>(); |
| } |
| DiagnosticChain entryFeatureDiagnostic = entryFeatureToDiagnosticChainMap.get(entryFeature); |
| if (entryFeatureDiagnostic == null) |
| { |
| entryFeatureDiagnostic = createBadDataValueDiagnostic(eObject, (EAttribute)entryFeature, diagnostics, context); |
| entryFeatureToDiagnosticChainMap.put(entryFeature, entryFeatureDiagnostic); |
| } |
| rootValidator.validate(entryType, entryValue, entryFeatureDiagnostic, context); |
| } |
| } |
| } |
| } |
| } |
| else if (eAttribute.isMany()) |
| { |
| for (Iterator<?> i = ((List<?>)value).iterator(); i.hasNext() && result; ) |
| { |
| result &= rootValidator.validate(eDataType, i.next(), null, context); |
| } |
| |
| if (!result && diagnostics != null) |
| { |
| DiagnosticChain diagnostic = createBadDataValueDiagnostic(eObject, eAttribute, diagnostics, context); |
| for (Iterator<?> i = ((List<?>)value).iterator(); i.hasNext(); ) |
| { |
| rootValidator.validate(eDataType, i.next(), diagnostic, context); |
| } |
| } |
| } |
| else if (value != null) |
| { |
| result = rootValidator.validate(eDataType, value, null, context); |
| if (!result && diagnostics != null) |
| { |
| DiagnosticChain diagnostic = createBadDataValueDiagnostic(eObject, eAttribute, diagnostics, context); |
| rootValidator.validate(eDataType, value, diagnostic, context); |
| } |
| } |
| |
| return result; |
| } |
| |
| protected DiagnosticChain createBadDataValueDiagnostic |
| (EObject eObject, EAttribute eAttribute, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| BasicDiagnostic diagnostic = |
| createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_DATA_VALUE_CONFORMS, |
| "_UI_BadDataValue_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eAttribute, context), |
| getObjectLabel(eObject, context) |
| }, |
| new Object [] { eObject, eAttribute }, |
| context); |
| diagnostics.add(diagnostic); |
| return diagnostic; |
| } |
| |
| protected boolean validatePattern |
| (EDataType eDataType, Object value, PatternMatcher [][] patterns, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| String literal = EcoreUtil.convertToString(eDataType, value); |
| for (int i = 0; i < patterns.length; ++i) |
| { |
| PatternMatcher [] children = patterns[i]; |
| boolean matches = false; |
| for (int j = 0; j < children.length; ++j) |
| { |
| if (children[j].matches(literal)) |
| { |
| matches = true; |
| break; |
| } |
| } |
| if (!matches) |
| { |
| if (diagnostics != null) |
| { |
| reportDataValuePatternViolation(eDataType, value, children, diagnostics, context); |
| } |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public class DynamicEDataTypeValidator |
| { |
| protected List<Object> effectiveEnumeration; |
| protected PatternMatcher [][] effectivePattern; |
| protected int effectiveTotalDigits = -1; |
| protected int effectiveFractionDigits = -1; |
| protected int effectiveMinLength = -1; |
| protected int effectiveMaxLength = -1; |
| protected Object effectiveMin; |
| protected boolean effectiveMinIsInclusive; |
| protected int effectiveTotalDigitsMin = -1; |
| protected Object effectiveMax; |
| protected boolean effectiveMaxIsInclusive; |
| protected int effectiveTotalDigitsMax = -1; |
| protected EDataType builtinType; |
| protected EDataType itemType; |
| protected List<EDataType> memberTypes; |
| |
| public DynamicEDataTypeValidator(EDataType eDataType) |
| { |
| ExtendedMetaData extendedMetaData = ExtendedMetaData.INSTANCE; |
| Resource resource = eDataType.eResource(); |
| if (resource != null) |
| { |
| ResourceSet resourceSet = resource.getResourceSet(); |
| if (resourceSet != null) |
| { |
| extendedMetaData = new BasicExtendedMetaData(resourceSet.getPackageRegistry()); |
| } |
| } |
| |
| List<PatternMatcher[]> patterns = null; |
| |
| for (;;) |
| { |
| if (effectiveEnumeration == null) |
| { |
| List<String> enumeration = extendedMetaData.getEnumerationFacet(eDataType); |
| if (!enumeration.isEmpty()) |
| { |
| effectiveEnumeration = new ArrayList<Object>(); |
| for (String enumerator : enumeration) |
| { |
| effectiveEnumeration.add(EcoreUtil.createFromString(eDataType, enumerator)); |
| } |
| } |
| } |
| |
| List<String> pattern = extendedMetaData.getPatternFacet(eDataType); |
| if (!pattern.isEmpty()) |
| { |
| if (patterns == null) |
| { |
| patterns = new ArrayList<PatternMatcher[]>(); |
| } |
| PatternMatcher [] children = new PatternMatcher [pattern.size()]; |
| patterns.add(children); |
| for (ListIterator<String> i = pattern.listIterator(); i.hasNext(); ) |
| { |
| PatternMatcher patternMatcher = XMLTypeUtil.createPatternMatcher(i.next()); |
| children[i.previousIndex()] = patternMatcher; |
| } |
| } |
| |
| if (effectiveTotalDigits == -1) |
| { |
| effectiveTotalDigits = extendedMetaData.getTotalDigitsFacet(eDataType); |
| } |
| if (effectiveFractionDigits == -1) |
| { |
| effectiveFractionDigits = extendedMetaData.getFractionDigitsFacet(eDataType); |
| } |
| if (effectiveMinLength == -1) |
| { |
| effectiveMinLength = extendedMetaData.getLengthFacet(eDataType); |
| if (effectiveMinLength == -1) |
| { |
| effectiveMinLength = extendedMetaData.getMinLengthFacet(eDataType); |
| } |
| } |
| if (effectiveMaxLength == -1) |
| { |
| effectiveMaxLength = extendedMetaData.getLengthFacet(eDataType); |
| if (effectiveMaxLength == -1) |
| { |
| effectiveMaxLength = extendedMetaData.getMaxLengthFacet(eDataType); |
| } |
| } |
| if (effectiveMin == null) |
| { |
| effectiveMin = extendedMetaData.getMinExclusiveFacet(eDataType); |
| if (effectiveMin == null) |
| { |
| effectiveMin = extendedMetaData.getMinInclusiveFacet(eDataType); |
| if (effectiveMin != null) |
| { |
| effectiveMin = EcoreUtil.createFromString(eDataType, (String)effectiveMin); |
| effectiveMinIsInclusive = true; |
| } |
| } |
| else |
| { |
| effectiveMin = EcoreUtil.createFromString(eDataType, (String)effectiveMin); |
| effectiveMinIsInclusive = false; |
| } |
| } |
| if (effectiveMax == null) |
| { |
| effectiveMax = extendedMetaData.getMaxExclusiveFacet(eDataType); |
| if (effectiveMax == null) |
| { |
| effectiveMax = extendedMetaData.getMaxInclusiveFacet(eDataType); |
| if (effectiveMax != null) |
| { |
| effectiveMax = EcoreUtil.createFromString(eDataType, (String)effectiveMax); |
| effectiveMaxIsInclusive = true; |
| } |
| } |
| else |
| { |
| effectiveMax = EcoreUtil.createFromString(eDataType, (String)effectiveMax); |
| effectiveMaxIsInclusive = false; |
| } |
| } |
| |
| EDataType baseType = extendedMetaData.getBaseType(eDataType); |
| if (baseType != null) |
| { |
| eDataType = baseType; |
| if (eDataType.getEPackage() == XMLTypePackage.eINSTANCE && eDataType.getInstanceClassName() == "javax.xml.datatype.XMLGregorianCalendar") |
| { |
| builtinType = eDataType; |
| itemType = null; |
| memberTypes = Collections.emptyList(); |
| break; |
| } |
| else |
| { |
| continue; |
| } |
| } |
| else |
| { |
| itemType = extendedMetaData.getItemType(eDataType); |
| memberTypes = extendedMetaData.getMemberTypes(eDataType); |
| break; |
| } |
| } |
| |
| if (patterns != null) |
| { |
| effectivePattern = new PatternMatcher [patterns.size()][]; |
| patterns.toArray(effectivePattern); |
| } |
| |
| if (effectiveTotalDigits != -1 && eDataType.getInstanceClassName() != "java.math.BigDecimal") |
| { |
| StringBuffer digits = new StringBuffer("1"); |
| for (int i = effectiveTotalDigits; i > 0; --i) |
| { |
| digits.append("0"); |
| } |
| |
| try |
| { |
| Object lowerBound = EcoreUtil.createFromString(eDataType, "-" + digits.toString()); |
| @SuppressWarnings("unchecked") boolean lowerBounded = effectiveMin == null || |
| (effectiveMinIsInclusive ? |
| ((Comparable<Object>)effectiveMin).compareTo(lowerBound) <= 0: |
| ((Comparable<Object>)effectiveMin).compareTo(lowerBound) < 0); |
| if (lowerBounded) |
| { |
| effectiveMinIsInclusive = false; |
| effectiveMin = lowerBound; |
| effectiveTotalDigitsMin = effectiveTotalDigits; |
| } |
| } |
| catch (NumberFormatException exception) |
| { |
| // Ignore the bound if the value is too big. |
| } |
| |
| try |
| { |
| Object upperBound = EcoreUtil.createFromString(eDataType, digits.toString()); |
| @SuppressWarnings("unchecked") boolean upperBounded = effectiveMax == null || |
| (effectiveMaxIsInclusive ? |
| ((Comparable<Object>)effectiveMax).compareTo(upperBound) >= 0: |
| ((Comparable<Object>)effectiveMax).compareTo(upperBound) > 0); |
| if (upperBounded) |
| { |
| effectiveMaxIsInclusive = false; |
| effectiveMax = upperBound; |
| effectiveTotalDigitsMax = effectiveTotalDigits; |
| } |
| } |
| catch (NumberFormatException exception) |
| { |
| // Ignore the bound if the value is too big. |
| } |
| |
| effectiveTotalDigits = -1; |
| } |
| |
| if (effectiveFractionDigits != -1 && eDataType.getInstanceClassName() != "java.math.BigDecimal") |
| { |
| effectiveFractionDigits = -1; |
| } |
| } |
| |
| protected boolean validateDelegatedConstraints(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| List<String> validationDelegates = EcoreUtil.getValidationDelegates(eDataType.getEPackage()); |
| |
| if (!validationDelegates.isEmpty()) |
| { |
| CONSTRAINTS: for (String constraint : EcoreUtil.getConstraints(eDataType)) |
| { |
| for (String validationDelegate : validationDelegates) |
| { |
| String expression = EcoreUtil.getAnnotation(eDataType, validationDelegate, constraint); |
| if (expression != null) |
| { |
| result &= EObjectValidator.this.validate(eDataType, value, diagnostics, context, validationDelegate, constraint, expression, Diagnostic.ERROR, DIAGNOSTIC_SOURCE, 0); |
| if (!result && diagnostics == null) |
| break CONSTRAINTS; |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| protected boolean validateSchemaConstraints(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| |
| if (effectiveEnumeration != null) |
| { |
| if (!effectiveEnumeration.contains(value)) |
| { |
| if (diagnostics != null) |
| reportEnumerationViolation(eDataType, value, effectiveEnumeration, diagnostics, context); |
| result = false; |
| } |
| } |
| |
| if (effectivePattern != null) |
| { |
| result = validatePattern(eDataType, value, effectivePattern, diagnostics, context); |
| } |
| |
| if (effectiveMin != null) |
| { |
| @SuppressWarnings("unchecked") |
| Comparable<Object> comparableObject = (Comparable<Object>)effectiveMin; |
| if (effectiveMinIsInclusive ? comparableObject.compareTo(value) > 0 : comparableObject.compareTo(value) >= 0) |
| { |
| if (diagnostics != null) |
| { |
| if (effectiveTotalDigitsMin != -1) |
| { |
| reportTotalDigitsViolation(eDataType, value, effectiveTotalDigitsMin, diagnostics, context); |
| } |
| else |
| { |
| reportMinViolation(eDataType, value, effectiveMin, effectiveMinIsInclusive, diagnostics, context); |
| } |
| } |
| result = false; |
| } |
| } |
| |
| if (effectiveMax != null) |
| { |
| @SuppressWarnings("unchecked") |
| Comparable<Object> comparableObject = (Comparable<Object>)effectiveMax; |
| if (effectiveMaxIsInclusive ? comparableObject.compareTo(value) < 0 : comparableObject.compareTo(value) <= 0) |
| { |
| if (diagnostics != null) |
| { |
| if (effectiveTotalDigitsMax != -1) |
| { |
| reportTotalDigitsViolation(eDataType, value, effectiveTotalDigitsMax, diagnostics, context); |
| } |
| else |
| { |
| reportMaxViolation(eDataType, value, effectiveMax, effectiveMaxIsInclusive, diagnostics, context); |
| } |
| } |
| result = false; |
| } |
| } |
| |
| if (effectiveMinLength != -1) |
| { |
| int length = |
| value instanceof String ? |
| ((String)value).length() : |
| value instanceof Collection<?> ? |
| ((Collection<?>)value).size() : |
| Array.getLength(value); |
| if (length < effectiveMinLength) |
| { |
| if (diagnostics != null) reportMinLengthViolation(eDataType, value, length, effectiveMinLength, diagnostics, context); |
| result = false; |
| } |
| } |
| |
| if (effectiveMaxLength != -1) |
| { |
| int length = |
| value instanceof String ? |
| ((String)value).length() : |
| value instanceof Collection<?> ? |
| ((Collection<?>)value).size() : |
| Array.getLength(value); |
| if (length > effectiveMaxLength) |
| { |
| if (diagnostics != null) reportMaxLengthViolation(eDataType, value, length, effectiveMaxLength, diagnostics, context); |
| result = false; |
| } |
| } |
| |
| if (effectiveTotalDigits != -1) |
| { |
| if (value instanceof BigDecimal) |
| { |
| BigDecimal bigDecimal = (BigDecimal)value; |
| int scale = bigDecimal.scale(); |
| int totalDigits = scale < 0 ? bigDecimal.precision() - scale : bigDecimal.precision(); |
| if (totalDigits > effectiveTotalDigits) |
| { |
| if (diagnostics != null) reportTotalDigitsViolation(eDataType, value, effectiveTotalDigits, diagnostics, context); |
| result = false; |
| } |
| } |
| } |
| |
| if (effectiveFractionDigits != -1) |
| { |
| if (value instanceof BigDecimal && ((BigDecimal)value).scale() > effectiveFractionDigits) |
| { |
| if (diagnostics != null) reportFractionDigitsViolation(eDataType, value, effectiveFractionDigits, diagnostics, context); |
| result = false; |
| } |
| } |
| |
| if (builtinType != null) |
| { |
| EValidator rootValidator = getRootEValidator(context); |
| result &= rootValidator.validate(builtinType, value, diagnostics, context); |
| } |
| |
| return result; |
| } |
| |
| public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = validateDelegatedConstraints(eDataType, value, diagnostics, context); |
| |
| if (result || diagnostics != null) |
| { |
| result &= validateSchemaConstraints(eDataType, value, diagnostics, context); |
| |
| if (itemType != null) |
| { |
| EValidator rootValidator = getRootEValidator(context); |
| for (Iterator< ? > i = ((List< ? >)value).iterator(); i.hasNext() && (result || diagnostics != null);) |
| { |
| result &= rootValidator.validate(itemType, i.next(), diagnostics, context); |
| } |
| return result; |
| } |
| else if (!memberTypes.isEmpty()) |
| { |
| EValidator rootValidator = getRootEValidator(context); |
| |
| for (EDataType memberType : memberTypes) |
| { |
| if (rootValidator.validate(memberType, value, null, context)) |
| { |
| return true; |
| } |
| } |
| for (EDataType memberType : memberTypes) |
| { |
| if (memberType.isInstance(value)) |
| { |
| return rootValidator.validate(memberType, value, diagnostics, context); |
| } |
| } |
| return false; |
| } |
| else |
| { |
| return result; |
| } |
| } |
| |
| return result; |
| } |
| } |
| |
| public class DynamicEClassValidator |
| { |
| protected boolean validateDelegatedInvariants(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| List<String> validationDelegates = EcoreUtil.getValidationDelegates(eClass.getEPackage()); |
| |
| if (!validationDelegates.isEmpty()) |
| { |
| INVARIANTS: for (EOperation eOperation : eClass.getEOperations()) |
| { |
| if (EcoreUtil.isInvariant(eOperation)) |
| { |
| for (String validationDelegate : validationDelegates) |
| { |
| String expression = EcoreUtil.getAnnotation(eOperation, validationDelegate, "body"); |
| if (expression != null) |
| { |
| result &= EObjectValidator.validate(eClass, eObject, diagnostics, context, validationDelegate, eOperation, expression, Diagnostic.ERROR, DIAGNOSTIC_SOURCE, 0); |
| if (!result && diagnostics == null) |
| break INVARIANTS; |
| } |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| protected boolean validateDelegatedConstraints(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| List<String> validationDelegates = EcoreUtil.getValidationDelegates(eClass.getEPackage()); |
| |
| if (!validationDelegates.isEmpty()) |
| { |
| CONSTRAINTS: for (String constraint : EcoreUtil.getConstraints(eClass)) |
| { |
| for (String validationDelegate : validationDelegates) |
| { |
| String expression = EcoreUtil.getAnnotation(eClass, validationDelegate, constraint); |
| if (expression != null) |
| { |
| result &= EObjectValidator.this.validate(eClass, eObject, diagnostics, context, validationDelegate, constraint, expression, Diagnostic.ERROR, DIAGNOSTIC_SOURCE, 0); |
| if (!result && diagnostics == null) |
| break CONSTRAINTS; |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = validateDelegatedInvariants(eClass, eObject, diagnostics, context); |
| |
| if (result || diagnostics != null) |
| { |
| result &= validateDelegatedConstraints(eClass, eObject, diagnostics, context); |
| |
| if (result || diagnostics != null) |
| { |
| List<EClass> eSuperTypes = eClass.getESuperTypes(); |
| result &= eSuperTypes.isEmpty() ? |
| validate_EveryDefaultConstraint(eObject, diagnostics, context) : |
| eClass.eContainer() == getEPackage() ? |
| EObjectValidator.this.validate(eClass.getClassifierID(), eObject, diagnostics, context) : |
| validate(eSuperTypes.get(0), eObject, diagnostics, context); |
| } |
| } |
| |
| return result; |
| } |
| } |
| |
| public boolean validate(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| if (!eDataType.isInstance(value)) |
| { |
| if (value == null) |
| { |
| return true; |
| } |
| else |
| { |
| if (diagnostics != null) reportDataValueTypeViolation(eDataType, value, diagnostics, context); |
| return false; |
| } |
| } |
| |
| if (eDataType.eContainer() == getEPackage()) |
| { |
| return validate(eDataType.getClassifierID(), value, diagnostics, context); |
| } |
| else |
| { |
| return |
| new DynamicEDataTypeValidator(eDataType) |
| { |
| // Ensure that the class loader for this class will be used downstream. |
| // |
| }.validate(eDataType, value, diagnostics, context); |
| } |
| } |
| |
| protected void reportMinViolation |
| (EDataType eDataType, Object value, Object bound, boolean isInclusive, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| DATA_VALUE__VALUE_IN_RANGE, |
| isInclusive ? "_UI_MinInclusiveConstraint_diagnostic" : "_UI_MinExclusiveConstraint_diagnostic", |
| new Object [] |
| { |
| getValueLabel(eDataType, value, context), |
| isInclusive ? ">=" : ">", |
| getValueLabel(eDataType, bound, context) |
| }, |
| new Object [] { value, bound, isInclusive ? Boolean.TRUE : Boolean.FALSE }, |
| context)); |
| } |
| |
| protected void reportMaxViolation |
| (EDataType eDataType, Object value, Object bound, boolean isInclusive, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| DATA_VALUE__VALUE_IN_RANGE, |
| isInclusive ? "_UI_MaxInclusiveConstraint_diagnostic" : "_UI_MaxExclusiveConstraint_diagnostic", |
| new Object [] |
| { |
| getValueLabel(eDataType, value, context), |
| "<", |
| getValueLabel(eDataType, bound, context) |
| }, |
| new Object [] { value, bound, isInclusive ? Boolean.TRUE : Boolean.FALSE }, |
| context)); |
| } |
| |
| protected void reportMinLengthViolation |
| (EDataType eDataType, Object value, int length, int bound, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| DATA_VALUE__LENGTH_IN_RANGE, |
| "_UI_MinLengthConstraint_diagnostic", |
| new Object [] |
| { |
| getValueLabel(eDataType, value, context), |
| Integer.toString(length), |
| Integer.toString(bound) |
| }, |
| new Object [] { value, eDataType, length, bound }, |
| context)); |
| } |
| |
| protected void reportMaxLengthViolation |
| (EDataType eDataType, Object value, int length, int bound, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| DATA_VALUE__LENGTH_IN_RANGE, |
| "_UI_MaxLengthConstraint_diagnostic", |
| new Object [] |
| { |
| getValueLabel(eDataType, value, context), |
| Integer.toString(length), |
| Integer.toString(bound) |
| }, |
| new Object [] { value, eDataType, length, bound }, |
| context)); |
| } |
| |
| protected void reportTotalDigitsViolation |
| (EDataType eDataType, Object value, int totalDigits, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| DATA_VALUE__TOTAL_DIGITS_IN_RANGE, |
| "_UI_TotalDigitsConstraint_diagnostic", |
| new Object [] |
| { |
| getValueLabel(eDataType, value, context), |
| totalDigits |
| }, |
| new Object [] { value, eDataType, totalDigits }, |
| context)); |
| } |
| |
| protected void reportFractionDigitsViolation |
| (EDataType eDataType, Object value, int fractionDigits, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| DATA_VALUE__FRACTION_DIGITS_IN_RANGE, |
| "_UI_FractionDigitsConstraint_diagnostic", |
| new Object [] |
| { |
| getValueLabel(eDataType, value, context), |
| fractionDigits |
| }, |
| new Object [] { value, eDataType, fractionDigits }, |
| context)); |
| } |
| |
| protected void reportEnumerationViolation |
| (EDataType eDataType, Object value, Collection<?> values, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| String valueLiterals = ""; |
| Iterator<?> i = values.iterator(); |
| if (i.hasNext()) |
| { |
| valueLiterals = |
| getEcoreResourceLocator().getString("_UI_ListHead_composition", new Object [] { getValueLabel(eDataType, i.next(), context) }); |
| while (i.hasNext()) |
| { |
| valueLiterals = |
| getEcoreResourceLocator().getString |
| ("_UI_ListTail_composition", |
| new Object [] { valueLiterals, getValueLabel(eDataType, i.next(), context) }); |
| } |
| } |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| DATA_VALUE__VALUE_IN_ENUMERATION, |
| "_UI_EnumerationConstraint_diagnostic", |
| new Object [] |
| { |
| getValueLabel(eDataType, value, context), |
| valueLiterals |
| }, |
| new Object [] { value, eDataType, values }, |
| context)); |
| } |
| |
| protected void reportDataValuePatternViolation |
| (EDataType eDataType, Object value, PatternMatcher [] patterns, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| String patternLiterals = ""; |
| if (patterns.length > 0) |
| { |
| patternLiterals = getEcoreResourceLocator().getString("_UI_ListHead_composition", new Object [] { patterns[0] }); |
| for (int i = 1; i < patterns.length; ++i) |
| { |
| patternLiterals = getEcoreResourceLocator().getString("_UI_ListTail_composition", new Object [] { patternLiterals, patterns[i] }); |
| } |
| } |
| |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| DATA_VALUE__MATCHES_PATTERN, |
| "_UI_PatternConstraint_diagnostic", |
| new Object [] |
| { |
| getValueLabel(eDataType, value, context), |
| patternLiterals |
| }, |
| new Object [] { value, eDataType, patterns }, |
| context)); |
| } |
| |
| protected void reportDataValueTypeViolation |
| (EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| DATA_VALUE__TYPE_CORRECT, |
| "_UI_BadDataValueType_diagnostic", |
| new Object [] |
| { |
| getValueLabel(eDataType, value, context), |
| value == null ? "<null>" : value.getClass().getName(), |
| eDataType.getInstanceClassName() |
| }, |
| new Object [] { value, eDataType }, |
| context)); |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected void reportConstraintDelegateViolation(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context, String constraint, int severity, String source, int code) |
| { |
| diagnostics.add |
| (new BasicDiagnostic |
| (severity, |
| source, |
| code, |
| getString("_UI_GenericConstraint_diagnostic", new Object[] { constraint, getValueLabel(eDataType, value, context) }), |
| new Object [] { value })); |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected void reportConstraintDelegateException(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context, String constraint, int severity, String source, int code, Throwable throwable) |
| { |
| diagnostics.add |
| (new BasicDiagnostic |
| (severity, |
| source, |
| code, |
| getString("_UI_ConstraintDelegateException_diagnostic", new Object[] { constraint, getValueLabel(eDataType, value, context), throwable.getClass().getName() + ": " + throwable.getLocalizedMessage() }), |
| new Object [] { value, throwable })); |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected void reportConstraintDelegateNotFound(EDataType eDataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context, String constraint, int severity, String source, int code, String validationDelegate) |
| { |
| diagnostics.add |
| (new BasicDiagnostic |
| (severity, |
| source, |
| code, |
| getString("_UI_ConstraintDelegateNotFound_diagnostic", new Object[] { constraint, getValueLabel(eDataType, value, context), validationDelegate }), |
| new Object [] { value })); |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected void reportConstraintDelegateViolation(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context, String constraint, int severity, String source, int code) |
| { |
| diagnostics.add |
| (new BasicDiagnostic |
| (severity, |
| source, |
| code, |
| getString("_UI_GenericConstraint_diagnostic", new Object[] { constraint, getObjectLabel(eObject, context) }), |
| new Object [] { eObject })); |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected void reportConstraintDelegateException(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context, String constraint, int severity, String source, int code, Throwable throwable) |
| { |
| diagnostics.add |
| (new BasicDiagnostic |
| (severity, |
| source, |
| code, |
| getString("_UI_ConstraintDelegateException_diagnostic", new Object[] { constraint, getObjectLabel(eObject, context), throwable.getClass().getName() + ": " + throwable.getLocalizedMessage() }), |
| new Object [] { eObject, throwable })); |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected void reportConstraintDelegateNotFound(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context, String constraint, int severity, String source, int code, String validationDelegate) |
| { |
| diagnostics.add |
| (new BasicDiagnostic |
| (severity, |
| source, |
| code, |
| getString("_UI_ConstraintDelegateNotFound_diagnostic", new Object[] { constraint, getObjectLabel(eObject, context), validationDelegate }), |
| new Object [] { eObject })); |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected static void reportInvariantDelegateViolation(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context, EOperation invariant, int severity, String source, int code) |
| { |
| diagnostics.add |
| (new BasicDiagnostic |
| (severity, |
| source, |
| code, |
| EcorePlugin.INSTANCE.getString("_UI_GenericInvariant_diagnostic", new Object[] { invariant.getName(), getObjectLabel(eObject, context) }), |
| new Object [] { eObject })); |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected static void reportInvariantDelegateException(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context, EOperation invariant, int severity, String source, int code, Throwable throwable) |
| { |
| diagnostics.add |
| (new BasicDiagnostic |
| (severity, |
| source, |
| code, |
| EcorePlugin.INSTANCE.getString("_UI_InvariantDelegateException_diagnostic", new Object[] { invariant.getName(), getObjectLabel(eObject, context), throwable.getClass().getName() + ": " + throwable.getLocalizedMessage() }), |
| new Object [] { eObject, throwable })); |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected static void reportInvariantDelegateNotFound(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context, EOperation invariant, int severity, String source, int code, String validationDelegate) |
| { |
| diagnostics.add |
| (new BasicDiagnostic |
| (severity, |
| source, |
| code, |
| EcorePlugin.INSTANCE.getString("_UI_InvariantDelegateNotFound_diagnostic", new Object[] { invariant.getName(), getObjectLabel(eObject, context), validationDelegate }), |
| new Object [] { eObject })); |
| } |
| |
| protected static Collection<Object> wrapEnumerationValues(Object [] values) |
| { |
| return java.util.Arrays.asList(values); |
| } |
| |
| /** |
| * @since 2.2 |
| */ |
| public boolean validate_UniqueID(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| String id = EcoreUtil.getID(eObject); |
| if (id != null) |
| { |
| Resource resource = eObject.eResource(); |
| if (resource != null) |
| { |
| EObject otherEObject = resource.getEObject(id); |
| if (eObject != otherEObject && otherEObject != null) |
| { |
| result = false; |
| if (diagnostics != null) |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__UNIQUE_ID, |
| "_UI_DuplicateID_diagnostic", |
| new Object [] |
| { |
| id, |
| getObjectLabel(eObject, context), |
| getObjectLabel(otherEObject, context) |
| }, |
| new Object [] { eObject, otherEObject, id }, |
| context)); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * @since 2.3 |
| * @param eObject |
| * @param diagnostics |
| * @param context |
| * @return whether every key is unique. |
| */ |
| public boolean validate_EveryKeyUnique(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| EClass eClass = eObject.eClass(); |
| for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i) |
| { |
| EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(i); |
| if (eStructuralFeature instanceof EReference) |
| { |
| EReference eReference = (EReference)eStructuralFeature; |
| if (eReference.isMany() && !eReference.getEKeys().isEmpty()) |
| { |
| result &= validate_KeyUnique(eObject, eReference, diagnostics, context); |
| if (!result && diagnostics == null) |
| { |
| return false; |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * @since 2.3 |
| * @param eObject |
| * @param eReference |
| * @param diagnostics |
| * @param context |
| * @return whether every key is unique. |
| */ |
| protected boolean validate_KeyUnique |
| (EObject eObject, EReference eReference, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| Map<List<Object>, EObject> keys = new HashMap<List<Object>, EObject>(); |
| EAttribute [] eAttributes = (EAttribute[])((BasicEList<?>)eReference.getEKeys()).data(); |
| @SuppressWarnings("unchecked") |
| List<EObject> values = (List<EObject>)eObject.eGet(eReference); |
| for (EObject value : values) |
| { |
| ArrayList<Object> key = new ArrayList<Object>(); |
| for (int i = 0, size = eAttributes.length; i < size; ++i) |
| { |
| EAttribute eAttribute = eAttributes[i]; |
| if (eAttribute == null) |
| { |
| break; |
| } |
| else |
| { |
| key.add(value.eGet(eAttribute)); |
| } |
| } |
| EObject otherValue = keys.put(key, value); |
| if (otherValue != null) |
| { |
| result = false; |
| if (diagnostics == null) |
| { |
| break; |
| } |
| else |
| { |
| String uriFragmentSegment = ((InternalEObject)eObject).eURIFragmentSegment(eReference, value); |
| int index = uriFragmentSegment.indexOf('[', 0); |
| if (index != -1) |
| { |
| uriFragmentSegment = uriFragmentSegment.substring(index); |
| } |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_KEY_UNIQUE, |
| "_UI_DuplicateKey_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eReference, context), |
| uriFragmentSegment, |
| getObjectLabel(value, context), |
| getObjectLabel(otherValue, context) |
| }, |
| new Object [] { eObject, eReference, value, otherValue }, |
| context)); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @since 2.3 |
| * @param eObject |
| * @param diagnostics |
| * @param context |
| * @return whether every map entry is unique. |
| */ |
| public boolean validate_EveryMapEntryUnique(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| EClass eClass = eObject.eClass(); |
| for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i) |
| { |
| EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(i); |
| if (eStructuralFeature.getEType().getInstanceClassName() == "java.util.Map$Entry" && eStructuralFeature instanceof EReference) |
| { |
| EReference eReference = (EReference)eStructuralFeature; |
| result &= validate_MapEntryUnique(eObject, eReference, diagnostics, context); |
| if (!result && diagnostics == null) |
| { |
| return false; |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * @since 2.3 |
| * @param eObject |
| * @param eReference |
| * @param diagnostics |
| * @param context |
| * @return whether every map entry is unique. |
| */ |
| protected boolean validate_MapEntryUnique |
| (EObject eObject, EReference eReference, DiagnosticChain diagnostics, Map<Object, Object> context) |
| { |
| boolean result = true; |
| Object value = eObject.eGet(eReference); |
| if (value instanceof EMap<?, ?>) |
| { |
| EMap<?, ?> eMap = (EMap<?, ?>)value; |
| for (int i = 0, size = eMap.size(); i < size; ++i) |
| { |
| Map.Entry<?, ?> entry = eMap.get(i); |
| Object key = entry.getKey(); |
| int index = eMap.indexOfKey(key); |
| if (index != i) |
| { |
| result = false; |
| if (diagnostics == null) |
| { |
| break; |
| } |
| else |
| { |
| diagnostics.add |
| (createDiagnostic |
| (Diagnostic.ERROR, |
| DIAGNOSTIC_SOURCE, |
| EOBJECT__EVERY_MAP_ENTRY_UNIQUE, |
| "_UI_DuplicateMapEntry_diagnostic", |
| new Object [] |
| { |
| getFeatureLabel(eReference, context), |
| i, |
| index |
| }, |
| new Object [] { eObject, eReference, entry, eMap.get(index) }, |
| context)); |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Creates a new {@link BasicDiagnostic#BasicDiagnostic(int, String, int, String, Object[]) basic diagnostic}. |
| * If the source is {@link #DIAGNOSTIC_SOURCE "org.eclipse.emf.ecore"}, |
| * it calls {@link #getEcoreString(String, Object[])}; |
| * otherwise it calls {@link #getString(String, Object[])}. |
| * @param severity an indicator of the severity of the problem. |
| * @param source the unique identifier of the source. |
| * @param code the source-specific identity code. |
| * @param messageKey the key of the message. |
| * @param messageSubstitutions the substitutions for the key; <code>null</code> if there are no substitutions. |
| * @param data the data associated with the diagnostic |
| * @param context a place to cache information, if it's <code>null</code>, no cache is supported. |
| * @return a new diagnostic. |
| * @see BasicDiagnostic#BasicDiagnostic(int, String, int, String, Object[]) |
| * @since 2.4 |
| */ |
| protected BasicDiagnostic createDiagnostic |
| (int severity, String source, int code, String messageKey, Object[] messageSubstitutions, Object[] data, Map<Object, Object> context) |
| { |
| String message = |
| DIAGNOSTIC_SOURCE.equals(source) ? |
| getEcoreString(messageKey, messageSubstitutions) : |
| getString(messageKey, messageSubstitutions); |
| return new BasicDiagnostic(severity, source, code, message, data); |
| } |
| |
| /** |
| * Returns a translated message with the given substitutions. |
| * The {@link #getEcoreResourceLocator() Ecore resource locator} is used. |
| * @param key the key for the message. |
| * @param substitutions the substitutions for the key; <code>null</code> if there are no substitutions. |
| * @return the message. |
| * @since 2.4 |
| */ |
| protected String getEcoreString(String key, Object [] substitutions) |
| { |
| return getString(getEcoreResourceLocator(), key, substitutions); |
| } |
| |
| /** |
| * Returns the resource locator for {@link #getEcoreString(String, Object[]) fetching} Ecore-specific messages. |
| * @return the resource locator for fetching Ecore-specific messages. |
| * @since 2.2 |
| */ |
| protected ResourceLocator getEcoreResourceLocator() |
| { |
| return EcorePlugin.INSTANCE; |
| } |
| |
| /** |
| * @since 2.6 |
| */ |
| protected boolean isEcoreString(String key) |
| { |
| return "_UI_GenericConstraint_diagnostic".equals(key) || "_UI_GenericInvariant_diagnostic".equals(key) |
| || "_UI_ConstraintDelegateException_diagnostic".equals(key) || "_UI_InvariantDelegateException_diagnostic".equals(key) |
| || "_UI_ConstraintDelegateNotFound_diagnostic".equals(key) || "_UI_InvariantDelegateNotFound_diagnostic".equals(key); |
| } |
| |
| /** |
| * Returns a translated message with the given substitutions. |
| * The {@link #getResourceLocator() resource locator} is used. |
| * @param key the key for the message. |
| * @param substitutions the substitutions for the key; <code>null</code> if there are no substitutions. |
| * @return the message. |
| * @since 2.4 |
| */ |
| protected String getString(String key, Object [] substitutions) |
| { |
| return getString(isEcoreString(key) ? getEcoreResourceLocator() : getResourceLocator(), key, substitutions); |
| } |
| |
| /** |
| * Returns the resource locator for {@link #getString(String, Object[]) fetching} model-specific messages. |
| * This implementation returns the {@link #getEcoreResourceLocator() Ecore resource locator}; |
| * derived validators <b>must</b> override this to return the resource locator for their model. |
| * @return the resource locator for fetching model-specific messages. |
| * @since 2.4 |
| */ |
| protected ResourceLocator getResourceLocator() |
| { |
| return getEcoreResourceLocator(); |
| } |
| |
| private String getString(ResourceLocator resourceLocator, String key, Object [] substitutions) |
| { |
| return substitutions == null ? resourceLocator.getString(key) : resourceLocator.getString(key, substitutions); |
| } |
| |
| /** |
| * Composes a localized message from the collection of choices |
| * with each choice value surrounded by the given quote character, except if the choice value is {@code null}. |
| * Each choice value will be {@link String#valueOf(Object) converted} to a string, for {@code Class} value, it will use the class {@link Class#getName() name}. |
| * <p> |
| * Example usage with results for the default locale: |
| * </p> |
| * <pre> |
| * ({}, true, "'", Integer.MAX_INT) → none available |
| * ({"a", "b"}, true, "'", Integer.MAX_INT) → 'a' and 'b' |
| * ({"a", "b", "c"}, false, "", Integer.MAX_INT) → a, b, or c |
| * ({"a", "b", "c", "d"}, false, "", 3) -> → a, b, c, … |
| * </pre> |
| * @param choices a collection of choice values. |
| * @param inclusive whether this an inclusive choice, i.e., one or more possible, e.g., {@code 'and'}, or an exclusive choice, i.e., only one possible, e.g., {@code 'or'}. |
| * @param quote the quotation characters used to bracket each choice value; use the empty string for no quotations. |
| * @param limit the maximum number to compose before terminating with an ellipsis. |
| * @return a localized messages for the collection of choices. |
| * @since 2.14 |
| */ |
| public String getAvailableChoices(Collection<?> choices, boolean inclusive, String quote, int limit) |
| { |
| if (choices.isEmpty()) |
| { |
| return "none available"; |
| } |
| else if (choices.size() == 1) |
| { |
| return quote(choices.iterator().next(), quote); |
| } |
| else |
| { |
| Iterator<?> i = choices.iterator(); |
| String result = quote(i.next(), quote); |
| ResourceLocator ecoreResourceLocator = getEcoreResourceLocator(); |
| if (choices.size() == 2) |
| { |
| return getString(ecoreResourceLocator, "_UI_SimpleListTrivialOr_composition", new Object[] { result, quote(i.next(), quote) }); |
| } |
| |
| for (int count = 2; i.hasNext(); ++count) |
| { |
| String next = quote(i.next(), quote); |
| if (i.hasNext()) |
| { |
| result = getString(ecoreResourceLocator, "_UI_SimpleListIntermediate_composition", new Object[] { result, next }); |
| } |
| else |
| { |
| result = getString(ecoreResourceLocator, inclusive ? "_UI_SimpleListTailAnd_composition" : "_UI_SimpleListTailOr_composition", new Object[] { result, next }); |
| } |
| |
| if (count == limit) |
| { |
| result = getString(ecoreResourceLocator, "_UI_SimpleListTailLimited_composition", new Object[] { result }); |
| break; |
| } |
| } |
| return result; |
| } |
| } |
| |
| private static String quote(Object value, String quote) |
| { |
| return value == null ? "null" : quote + (value instanceof Class<?> ? ((Class<?>)value).getName() : value) + quote; |
| } |
| } |