blob: 5d13ac6662f903ccbcdcedb7c75cffba4fe86e85 [file] [log] [blame]
/**
* 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) &rarr; none available
* ({"a", "b"}, true, "'", Integer.MAX_INT) &rarr; 'a' and 'b'
* ({"a", "b", "c"}, false, "", Integer.MAX_INT) &rarr; a, b, or c
* ({"a", "b", "c", "d"}, false, "", 3) -> &rarr; a, b, c, &hellip;
* </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;
}
}