/**
 * Copyright (c) 2006-2012 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
 *   Christian Damus (Zeligsoft) - 255469
 */
package org.eclipse.emf.ecore.util;

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.UniqueEList;

import org.eclipse.emf.ecore.*;
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.namespace.XMLNamespacePackage;
import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
import org.eclipse.emf.ecore.xml.type.util.XMLTypeValidator;

/**
 * <!-- begin-user-doc -->
 * The <b>Validator</b> for the model.
 * <!-- end-user-doc -->
 * @see org.eclipse.emf.ecore.EcorePackage
 * @generated
 */
public class EcoreValidator extends EObjectValidator
{
  /**
   * The cached model package
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public static final EcoreValidator INSTANCE = new EcoreValidator();

  /**
   * A key to be used in <code>context</code> maps to indicate that stricter validation should be performed 
   * to ensure that the name of each named element is a well formed Java identifier. 
   * The value of the entry must be a {@link Boolean}.
   * The default value is <code>Boolean.TRUE</code>.
   * @see EValidator#validate(EObject, DiagnosticChain, Map)
   * @see #validateENamedElement_WellFormedName(ENamedElement, DiagnosticChain, Map)
   * @since 2.4
   */
  public static final String STRICT_NAMED_ELEMENT_NAMES = "org.eclipse.emf.ecore.model.ENamedElement_WellFormedName";

  /**
   * A constant for the {@link org.eclipse.emf.common.util.Diagnostic#getSource() source} of diagnostic {@link org.eclipse.emf.common.util.Diagnostic#getCode() codes} from this package.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @see org.eclipse.emf.common.util.Diagnostic#getSource()
   * @see org.eclipse.emf.common.util.Diagnostic#getCode()
   * @generated NOT
   */
  public static final String DIAGNOSTIC_SOURCE = "org.eclipse.emf.ecore.model";

  /**
   * A constant with a fixed name that can be used as the base value for additional hand written constants.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  private static final int GENERATED_DIAGNOSTIC_CODE_COUNT = 0;

  /**
   * @see #validateEClass_AtMostOneID(EClass, DiagnosticChain, Map)
   */
  public static final int AT_MOST_ONE_ID = GENERATED_DIAGNOSTIC_CODE_COUNT + 1;

  /**
   * @see #validateEGenericType_ConsistentArguments(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_ARGUMENTS_INCORRECT_NUMBER = 2;

  /**
   * @see #validateEGenericType_ConsistentArguments(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_ARGUMENTS_INVALID_SUBSTITUTION = 3;

  /**
   * @see #validateEGenericType_ConsistentArguments(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_ARGUMENTS_NONE = 4;

  /**
   * @see #validateEGenericType_ConsistentArguments(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_ARGUMENTS_NONE_ALLOWED = 5;

  /**
   * @see #validateETypedElement_ConsistentBounds(ETypedElement, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_BOUNDS = 6;

  /**
   * @see #validateEGenericType_ConsistentBounds(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_BOUNDS_NOT_ALLOWED = 7;

  /**
   * @see #validateEGenericType_ConsistentBounds(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_BOUNDS_NO_BOUNDS_WITH_TYPE_PARAMETER_OR_CLASSIFIER = 8;

  /**
   * @see #validateEGenericType_ConsistentBounds(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_BOUNDS_NO_LOWER_AND_UPPER = 9;

  /**
   * @see #validateEReference_ConsistentKeys(EReference, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_KEYS = 10;

  /**
   * @see #validateEReference_ConsistentOpposite(EReference, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_OPPOSITE_BAD_TRANSIENT = 11;

  /**
   * @see #validateEReference_ConsistentOpposite(EReference, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_OPPOSITE_BOTH_CONTAINMENT = 12;

  /**
   * @see #validateEReference_ConsistentOpposite(EReference, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_OPPOSITE_NOT_FROM_TYPE = 13;

  /**
   * @see #validateEReference_ConsistentOpposite(EReference, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_OPPOSITE_NOT_MATCHING = 14;

  /**
   * @see #validateEClass_ConsistentSuperTypes(EClass, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_SUPER_TYPES_CONFLICT = 15;

  /**
   * @see #validateEClass_ConsistentSuperTypes(EClass, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_SUPER_TYPES_DUPLICATE = 16;

  /**
   * @see #validateEAttribute_ConsistentTransient(EAttribute, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_TRANSIENT = 17;

  /**
   * @see #validateEGenericType_ConsistentType(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_TYPE_CLASS_REQUIRED = 18;

  /**
   * @see #validateEGenericType_ConsistentType(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_TYPE_CLASS_NOT_PERMITTED = 19;

  /**
   * @see #validateEGenericType_ConsistentType(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_TYPE_DATA_TYPE_NOT_PERMITTED = 20;

  /**
   * @see #validateEGenericType_ConsistentType(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_TYPE_NO_TYPE_PARAMETER_AND_CLASSIFIER = 21;

  /**
   * @see #validateEGenericType_ConsistentType(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_TYPE_PRIMITIVE_TYPE_NOT_PERMITTED = 22;

  /**
   * @see #validateEGenericType_ConsistentType(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_TYPE_TYPE_PARAMETER_NOT_IN_SCOPE = 23;

  /**
   * @see #validateEGenericType_ConsistentType(EGenericType, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_TYPE_WILDCARD_NOT_PERMITTED = 24;

  /**
   * @see #validateEClass_InterfaceIsAbstract(EClass, DiagnosticChain, Map)
   */
  public static final int INTERFACE_IS_ABSTRACT = 25;

  /**
   * @see #validateEClass_NoCircularSuperTypes(EClass, DiagnosticChain, Map)
   */
  public static final int NO_CIRCULAR_SUPER_TYPES = 26;

  /**
   * @see #validateEOperation_NoRepeatingVoid(EOperation, DiagnosticChain, Map)
   */
  public static final int NO_REPEATING_VOID = 27;

  /**
   * @see #validateEReference_SingleContainer(EReference, DiagnosticChain, Map)
   */
  public static final int SINGLE_CONTAINER = 28;

  /**
   * @see #validateEPackage_UniqueClassifierNames(EPackage, DiagnosticChain, Map)
   */
  public static final int UNIQUE_CLASSIFIER_NAMES = 29;

  /**
   * @see #validateEEnum_UniqueEnumeratorNames(EEnum, DiagnosticChain, Map)
   */
  public static final int UNIQUE_ENUMERATOR_LITERALS = 30;

  /**
   * @see #validateEEnum_UniqueEnumeratorNames(EEnum, DiagnosticChain, Map)
   */
  public static final int UNIQUE_ENUMERATOR_NAMES = 31;

  /**
   * @see #validateEClass_UniqueFeatureNames(EClass, DiagnosticChain, Map)
   */
  public static final int UNIQUE_FEATURE_NAMES = 32;

  /**
   * @see #validateEPackage_UniqueNsURIs(EPackage, DiagnosticChain, Map)
   */
  public static final int UNIQUE_NS_URIS = 33;

  /**
   * @see #validateEClass_UniqueOperationSignatures(EClass, DiagnosticChain, Map)
   */
  public static final int UNIQUE_OPERATION_SIGNATURES = 34;

  /**
   *@see #validateEOperation_UniqueParameterNames(EOperation, DiagnosticChain, Map)
   */
  public static final int UNIQUE_PARAMETER_NAMES = 35;

  /**
   * @see #validateEPackage_UniqueSubpackageNames(EPackage, DiagnosticChain, Map)
   */
  public static final int UNIQUE_SUBPACKAGE_NAMES = 36;

  /**
   *@see #validateEOperation_UniqueParameterNames(EOperation, DiagnosticChain, Map)
   *@see #validateEClassifier_UniqueTypeParameterNames(EClassifier, DiagnosticChain, Map)
   */
  public static final int UNIQUE_TYPE_PARAMETER_NAMES = 37;

  /**
   * @see #validateEStructuralFeature_ValidDefaultValueLiteral(EStructuralFeature, DiagnosticChain, Map)
   */
  public static final int VALID_DEFAULT_VALUE_LITERAL = 38;

  /**
   * @see #validateETypedElement_ValidLowerBound(ETypedElement, DiagnosticChain, Map)
   */
  public static final int VALID_LOWER_BOUND = 39;

  /**
   * @see #validateETypedElement_ValidType(ETypedElement, DiagnosticChain, Map)
   */
  public static final int VALID_TYPE = 40;

  /**
   * @see #validateETypedElement_ValidUpperBound(ETypedElement, DiagnosticChain, Map)
   */
  public static final int VALID_UPPER_BOUND = 41;

  /**
   * @see #validateEClassifier_WellFormedInstanceTypeName(EClassifier, DiagnosticChain, Map)
   */
  public static final int WELL_FORMED_INSTANCE_TYPE_NAME = 42;

  /**
   * @see #validateEClass_WellFormedMapEntryClass(EClass, DiagnosticChain, Map)
   */
  public static final int WELL_FORMED_MAP_ENTRY_CLASS = 43;

  /**
   * @see #validateEClass_WellFormedMapEntryClass(EClass, DiagnosticChain, Map)
   */
  public static final int WELL_FORMED_NAME = 44;

  /**
   * @see #validateEPackage_WellFormedNsPrefix(EPackage, DiagnosticChain, Map)
   */
  public static final int WELL_FORMED_NS_PREFIX = 45;

  /**
   * @see #validateEPackage_WellFormedNsURI(EPackage, DiagnosticChain, Map)
   */
  public static final int WELL_FORMED_NS_URI = 46;

  /**
   * @see #validateEAnnotation_WellFormedSourceURI(EAnnotation, DiagnosticChain, Map)
   */
  public static final int WELL_FORMED_SOURCE_URI = 47;

  /**
   * @see #validateEClass_DisjointFeatureAndOperationSignatures(EClass, DiagnosticChain, Map)
   */
  public static final int DISJOINT_FEATURE_AND_OPERATION_SIGNATURES = 48;

  /**
   * @see #validateEClass_WellFormedMapEntryClass(EClass, DiagnosticChain, Map)
   */
  public static final int WELL_FORMED_MAP_ENTRY_NO_INSTANCE_CLASS_NAME = 49;

  /**
   * @see #validateEReference_ConsistentUnique(EReference, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_UNIQUE = 50;

  /**
   * @see #validateEReference_ConsistentContainer(EReference, DiagnosticChain, Map)
   */
  public static final int CONSISTENT_CONTAINER = 51;
  
  /**
   * A constant with a fixed name that can be used as the base value for additional hand written constants in a derived class.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated NOT
   */
  protected static final int DIAGNOSTIC_CODE_COUNT = CONSISTENT_CONTAINER;

  /**
   * The cached base package validator.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  protected XMLTypeValidator xmlTypeValidator;

  /**
   * Creates an instance of the switch.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public EcoreValidator()
  {
    super();
    xmlTypeValidator = XMLTypeValidator.INSTANCE;
  }

  /**
   * Returns the package of this validator switch.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  @Override
  protected EPackage getEPackage()
  {
    return EcorePackage.eINSTANCE;
  }

  /**
   * Calls <code>validateXXX</code> for the corresponding classifier of the model.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  @Override
  protected boolean validate(int classifierID, Object value, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    switch (classifierID)
    {
      case EcorePackage.EATTRIBUTE:
        return validateEAttribute((EAttribute)value, diagnostics, context);
      case EcorePackage.EANNOTATION:
        return validateEAnnotation((EAnnotation)value, diagnostics, context);
      case EcorePackage.ECLASS:
        return validateEClass((EClass)value, diagnostics, context);
      case EcorePackage.ECLASSIFIER:
        return validateEClassifier((EClassifier)value, diagnostics, context);
      case EcorePackage.EDATA_TYPE:
        return validateEDataType((EDataType)value, diagnostics, context);
      case EcorePackage.EENUM:
        return validateEEnum((EEnum)value, diagnostics, context);
      case EcorePackage.EENUM_LITERAL:
        return validateEEnumLiteral((EEnumLiteral)value, diagnostics, context);
      case EcorePackage.EFACTORY:
        return validateEFactory((EFactory)value, diagnostics, context);
      case EcorePackage.EMODEL_ELEMENT:
        return validateEModelElement((EModelElement)value, diagnostics, context);
      case EcorePackage.ENAMED_ELEMENT:
        return validateENamedElement((ENamedElement)value, diagnostics, context);
      case EcorePackage.EOBJECT:
        return validateEObject((EObject)value, diagnostics, context);
      case EcorePackage.EOPERATION:
        return validateEOperation((EOperation)value, diagnostics, context);
      case EcorePackage.EPACKAGE:
        return validateEPackage((EPackage)value, diagnostics, context);
      case EcorePackage.EPARAMETER:
        return validateEParameter((EParameter)value, diagnostics, context);
      case EcorePackage.EREFERENCE:
        return validateEReference((EReference)value, diagnostics, context);
      case EcorePackage.ESTRUCTURAL_FEATURE:
        return validateEStructuralFeature((EStructuralFeature)value, diagnostics, context);
      case EcorePackage.ETYPED_ELEMENT:
        return validateETypedElement((ETypedElement)value, diagnostics, context);
      case EcorePackage.ESTRING_TO_STRING_MAP_ENTRY:
        return validateEStringToStringMapEntry((Map.Entry<?, ?>)value, diagnostics, context);
      case EcorePackage.EGENERIC_TYPE:
        return validateEGenericType((EGenericType)value, diagnostics, context);
      case EcorePackage.ETYPE_PARAMETER:
        return validateETypeParameter((ETypeParameter)value, diagnostics, context);
      case EcorePackage.EBIG_DECIMAL:
        return validateEBigDecimal((BigDecimal)value, diagnostics, context);
      case EcorePackage.EBIG_INTEGER:
        return validateEBigInteger((BigInteger)value, diagnostics, context);
      case EcorePackage.EBOOLEAN:
        return validateEBoolean((Boolean)value, diagnostics, context);
      case EcorePackage.EBOOLEAN_OBJECT:
        return validateEBooleanObject((Boolean)value, diagnostics, context);
      case EcorePackage.EBYTE:
        return validateEByte((Byte)value, diagnostics, context);
      case EcorePackage.EBYTE_ARRAY:
        return validateEByteArray((byte[])value, diagnostics, context);
      case EcorePackage.EBYTE_OBJECT:
        return validateEByteObject((Byte)value, diagnostics, context);
      case EcorePackage.ECHAR:
        return validateEChar((Character)value, diagnostics, context);
      case EcorePackage.ECHARACTER_OBJECT:
        return validateECharacterObject((Character)value, diagnostics, context);
      case EcorePackage.EDATE:
        return validateEDate((Date)value, diagnostics, context);
      case EcorePackage.EDIAGNOSTIC_CHAIN:
        return validateEDiagnosticChain((DiagnosticChain)value, diagnostics, context);
      case EcorePackage.EDOUBLE:
        return validateEDouble((Double)value, diagnostics, context);
      case EcorePackage.EDOUBLE_OBJECT:
        return validateEDoubleObject((Double)value, diagnostics, context);
      case EcorePackage.EE_LIST:
        return validateEEList((EList<?>)value, diagnostics, context);
      case EcorePackage.EENUMERATOR:
        return validateEEnumerator((Enumerator)value, diagnostics, context);
      case EcorePackage.EFEATURE_MAP:
        return validateEFeatureMap((FeatureMap)value, diagnostics, context);
      case EcorePackage.EFEATURE_MAP_ENTRY:
        return validateEFeatureMapEntry((FeatureMap.Entry)value, diagnostics, context);
      case EcorePackage.EFLOAT:
        return validateEFloat((Float)value, diagnostics, context);
      case EcorePackage.EFLOAT_OBJECT:
        return validateEFloatObject((Float)value, diagnostics, context);
      case EcorePackage.EINT:
        return validateEInt((Integer)value, diagnostics, context);
      case EcorePackage.EINTEGER_OBJECT:
        return validateEIntegerObject((Integer)value, diagnostics, context);
      case EcorePackage.EJAVA_CLASS:
        return validateEJavaClass((Class<?>)value, diagnostics, context);
      case EcorePackage.EJAVA_OBJECT:
        return validateEJavaObject(value, diagnostics, context);
      case EcorePackage.ELONG:
        return validateELong((Long)value, diagnostics, context);
      case EcorePackage.ELONG_OBJECT:
        return validateELongObject((Long)value, diagnostics, context);
      case EcorePackage.EMAP:
        return validateEMap((Map<?, ?>)value, diagnostics, context);
      case EcorePackage.ERESOURCE:
        return validateEResource((Resource)value, diagnostics, context);
      case EcorePackage.ERESOURCE_SET:
        return validateEResourceSet((ResourceSet)value, diagnostics, context);
      case EcorePackage.ESHORT:
        return validateEShort((Short)value, diagnostics, context);
      case EcorePackage.ESHORT_OBJECT:
        return validateEShortObject((Short)value, diagnostics, context);
      case EcorePackage.ESTRING:
        return validateEString((String)value, diagnostics, context);
      case EcorePackage.ETREE_ITERATOR:
        return validateETreeIterator((TreeIterator<?>)value, diagnostics, context);
      case EcorePackage.EINVOCATION_TARGET_EXCEPTION:
        return validateEInvocationTargetException((InvocationTargetException)value, diagnostics, context);
      default:
        return true;
    }
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEAttribute(EAttribute eAttribute, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eAttribute, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidLowerBound(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidUpperBound(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ConsistentBounds(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidType(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validateEStructuralFeature_ValidDefaultValueLiteral(eAttribute, diagnostics, context);
    if (result || diagnostics != null) result &= validateEAttribute_ConsistentTransient(eAttribute, diagnostics, context);
    return result;
  }

  /**
   * Validates the ConsistentTransient constraint of '<em>EAttribute</em>'.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEAttribute_ConsistentTransient(EAttribute eAttribute, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    EDataType eAttributeType = eAttribute.getEAttributeType();
    boolean result = 
      isEffectivelyTransient(eAttribute) ||
        eAttributeType == null || 
        eAttributeType.isSerializable() ||
        FeatureMapUtil.isFeatureMapEntry(eAttributeType);
    if (!result && diagnostics != null)
    {
      String attributeName = eAttribute.getName();
      if (eAttribute.getEContainingClass() != null)
      {
        attributeName = eAttribute.getEContainingClass().getName() + "." + attributeName;
      }
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           CONSISTENT_TRANSIENT,
           "_UI_EAttributeConsistentTransient_diagnostic", 
           new String[] { attributeName },
           new Object[] { eAttribute, EcorePackage.Literals.ESTRUCTURAL_FEATURE__TRANSIENT },
           context));
    }
    return result;
  }
  
  private static boolean isEffectivelyTransient(EStructuralFeature eStructuralFeature)
  {
    if (eStructuralFeature.isTransient())
    {
      EStructuralFeature group = ExtendedMetaData.INSTANCE.getGroup(eStructuralFeature);
      return group == null || isEffectivelyTransient(group);
    }
    else
    {
      return false;
    }
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEAnnotation(EAnnotation eAnnotation, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eAnnotation, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eAnnotation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eAnnotation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eAnnotation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eAnnotation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eAnnotation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eAnnotation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eAnnotation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eAnnotation, diagnostics, context);
    if (result || diagnostics != null) result &= validateEAnnotation_WellFormed(eAnnotation, diagnostics, context);
    if (result || diagnostics != null) result &= validateEAnnotation_WellFormedSourceURI(eAnnotation, diagnostics, context);
    return result;
  }

  /**
   * Validates the WellFormed constraint of '<em>EAnnotation</em>'.
   * <!-- begin-user-doc -->
   * @since 2.14
   * @see EAnnotationValidator#validate(EAnnotation, DiagnosticChain, Map)
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEAnnotation_WellFormed(EAnnotation eAnnotation, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    EAnnotationValidator eAnnotationValidator = EAnnotationValidator.Registry.INSTANCE.getEAnnotationValidator(eAnnotation.getSource());
    if (eAnnotationValidator != null)
    {
      return eAnnotationValidator.validate(eAnnotation, diagnostics, context);
    }
    else
    {
      return true;
    }
  }

  /**
   * Validates the WellFormedSourceURI constraint of '<em>EAnnotation</em>'.
   * <!-- begin-user-doc -->
   * The source URI must either be either <code>null</code> or {@link #isWellFormedURI(String) well formed}.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEAnnotation_WellFormedSourceURI(EAnnotation eAnnotation, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    String source = eAnnotation.getSource();
    boolean result = source == null || isWellFormedURI(source);
    if (!result && diagnostics != null)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           WELL_FORMED_SOURCE_URI,
           "_UI_EAnnotationSourceURINotWellFormed_diagnostic",
           new Object[] { source },
           new Object[] { eAnnotation, EcorePackage.Literals.EANNOTATION__SOURCE },
           context));
    }
    return result;
  }

  /**
   * A well formed URI string must have a non-zero length,
   * and must encode any special characters such as the space character.
   * As such, creating a {@link URI#createURI(String, boolean) URI},
   * ignoring the properly encoded characters,
   * and converting that to a {@link URI#toString() string},
   * must yield this URI string itself.
   * @param uri the URI string in question.
   * @return whether the URI is well formed.
   */
  protected static boolean isWellFormedURI(String uri)
  {
    try
    {
      return uri != null && uri.length() != 0 && uri.equals(URI.createURI(uri, true).toString());
    }
    catch (Throwable exception)
    {
      return false;
    }
  }

  /**
   * A well formed Java identifier must start with a {@link Character#isJavaIdentifierStart(int) Java identifier start} character
   * followed by zero or more {@link Character#isJavaIdentifierPart(int) Java identifier part} characters.
   * @param name the name in question.
   * @return whether the name is a well formed Java identifier.
   * @since 2.14
   */
  public static boolean isWellFormedJavaIdentifier(String name)
  {
    boolean result = false;
    if (name != null)
    {
      int length = name.length();
      if (length > 0)
      {
        int codePoint = name.codePointAt(0);
        if (Character.isJavaIdentifierStart(codePoint) && codePoint != '$')
        {
          result = true;
          for (int i = Character.offsetByCodePoints(name, 0, 1); i < length; i = Character.offsetByCodePoints(name, i, 1))
          {
            codePoint = name.codePointAt(i);
            if (codePoint == '$' || !Character.isJavaIdentifierPart(codePoint))
            {
              result = false;
              break;
            }
          }
        }
      }
    }
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEClass(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eClass, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClassifier_WellFormedInstanceTypeName(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClassifier_UniqueTypeParameterNames(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClass_InterfaceIsAbstract(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClass_AtMostOneID(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClass_UniqueFeatureNames(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClass_UniqueOperationSignatures(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClass_NoCircularSuperTypes(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClass_WellFormedMapEntryClass(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClass_ConsistentSuperTypes(eClass, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClass_DisjointFeatureAndOperationSignatures(eClass, diagnostics, context);
    return result;
  }

  /**
   * Validates the InterfaceIsAbstract constraint of '<em>EClass</em>'.
   * <!-- begin-user-doc -->
   * A class that is an interface must be abstract.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClass_InterfaceIsAbstract(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = !eClass.isInterface() || eClass.isAbstract();
    if (!result && diagnostics != null)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           INTERFACE_IS_ABSTRACT,
           "_UI_EClassInterfaceNotAbstract_diagnostic",
           null,
           new Object[] { eClass, EcorePackage.Literals.ECLASS__ABSTRACT },
           context));
    }
    return result;
  }

  /**
   * Validates the AtMostOneID constraint of '<em>EClass</em>'.
   * <!-- begin-user-doc -->
   * There can be at most one attribute that is an ID.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClass_AtMostOneID(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    EAttribute eIDAttribute = eClass.getEIDAttribute();

    // A document root can have multiple ID attributes because there can be multiple global element or attribute declarations of type ID 
    // and these will be the ID in the complex types that reference them,
    // i.e., they aren't really the ID of the document root.
    //
    if (eIDAttribute != null && !ExtendedMetaData.INSTANCE.isDocumentRoot(eClass))
    {
      List<EAttribute> eIDAttributes = new ArrayList<EAttribute>();
      eIDAttributes.add(eIDAttribute);

      for (EAttribute eAttribute : eClass.getEAllAttributes())
      {
        if (eAttribute.isID() && eIDAttribute != eAttribute)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            eIDAttributes.add(eAttribute);
          }
        }
      }

      if (!result && diagnostics != null)
      {
        // We do not want to diagnose any errors that have already been diagnosed by a super type.
        //
        for (EClass eSuperType : eClass.getESuperTypes())
        {
          EList<EStructuralFeature> eAllStructuralFeatures = eSuperType.getEAllStructuralFeatures();
          if (eAllStructuralFeatures.containsAll(eIDAttributes))
          {
            return false;
          }
        }

        List<String> labels = new ArrayList<String>();
        List<Object> objects = new ArrayList<Object>();
        objects.add(eClass);
        for (EAttribute eAttribute : eIDAttributes)
        {
          labels.add(getFeatureLabel(eAttribute,context));
          objects.add(eAttribute);
        }
        objects.add(EcorePackage.Literals.ECLASS__EALL_ATTRIBUTES);
        diagnostics.add
          (createDiagnostic
            (Diagnostic.ERROR,
             DIAGNOSTIC_SOURCE,
             AT_MOST_ONE_ID,
             "_UI_EClassAtMostOneID_diagnostic",
             labels.toArray(new Object[labels.size()]),
             objects.toArray(new Object [objects.size()]),
             context));
      }
    }
    return result;
  }

  /**
   * Validates the UniqueFeatureNames constraint of '<em>EClass</em>'.
   * <!-- begin-user-doc -->
   * No two features may have matching names.
   * Feature names are matched ignoring their case and their underscore separators.
   * It is an error to have two features with names that are equal but only a warning to have two features with names that match.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClass_UniqueFeatureNames(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    int size = eClass.getFeatureCount();
    if (size > 0)
    {
      // Build a list of the keys
      //
      Map<String, List<EStructuralFeature>> keys = new HashMap<String, List<EStructuralFeature>>();
      for (int i = 0; i < size; ++i)
      {
        EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(i);
        String name = eStructuralFeature.getName();

        // Don't bother complaining about things with no name,  since there are constraints for that problem.
        //
        if (name != null)
        {
          // Drop the _ separators and normalize the case.
          //
          String key = name.replace("_", "").toLowerCase();
          List<EStructuralFeature> eStructuralFeatures = keys.get(key);
          if (eStructuralFeatures == null)
          {
            eStructuralFeatures = new ArrayList<EStructuralFeature>();
            keys.put(key, eStructuralFeatures);
          }
          eStructuralFeatures.add(eStructuralFeature);

          if (eStructuralFeatures.size() > 1)
          {
            if (diagnostics == null)
            {
              return false;
            }
            else
            {
              result = false;
            }
          }
        }
      }

      if (!result && diagnostics != null)
      {
        // We do not want to diagnose any errors that have already been diagnosed by a super type.
        //
        for (EClass eSuperType : eClass.getESuperTypes())
        {
          EList<EStructuralFeature> eAllStructuralFeatures = eSuperType.getEAllStructuralFeatures();
          for (Iterator<Map.Entry<String, List<EStructuralFeature>>> i = keys.entrySet().iterator(); i.hasNext(); )
          {
            Map.Entry<String, List<EStructuralFeature>> entry = i.next();
            if (eAllStructuralFeatures.containsAll(entry.getValue()))
            {
              i.remove();
            }
          }
        }
        
        for (Map.Entry<String, List<EStructuralFeature>> entry : keys.entrySet())
        {
          List<EStructuralFeature> eStructuralFeatures = entry.getValue();
          if (eStructuralFeatures.size() > 1)
          {
            List<String> names = new UniqueEList<String>();
            List<Object> objects = new ArrayList<Object>();
            objects.add(eClass);
            for (EStructuralFeature eStructuralFeature : eStructuralFeatures)
            {
              names.add(eStructuralFeature.getName());
              objects.add(eStructuralFeature);
            }
            objects.add(EcorePackage.Literals.ECLASS__EALL_STRUCTURAL_FEATURES);
            
            if (names.size() == objects.size() - 2)
            {
              diagnostics.add
                (createDiagnostic
                  (Diagnostic.WARNING,
                   DIAGNOSTIC_SOURCE,
                   UNIQUE_FEATURE_NAMES,
                   "_UI_EClassDissimilarEStructuralFeatureName_diagnostic",
                   names.toArray(new Object[names.size()]),
                   objects.toArray(new Object[objects.size()]),
                   context));
              
            }
            else
            {
              diagnostics.add
                (createDiagnostic
                  (Diagnostic.ERROR,
                   DIAGNOSTIC_SOURCE,
                   UNIQUE_FEATURE_NAMES,
                   "_UI_EClassUniqueEStructuralFeatureName_diagnostic",
                   new Object [] { names.get(0) },
                   objects.toArray(new Object[objects.size()]),
                   context));
            }
          }
        }
      }
    }
    return result;
  }

  /**
   * Validates the UniqueOperationSignatures constraint of '<em>EClass</em>'.
   * <!-- begin-user-doc -->
   * No two operations defined in the same class may have matching signatures.
   * The signature is determined by the name of the operation and the types of its parameters.
   * If the name is the same and the types match, the signatures match.
   * Types match if they are the same classifier, or both classifiers have instance class names that are the same.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClass_UniqueOperationSignatures(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return uniqueOperationSignaturesValidator.validateEOperationSignatures(eClass, eClass.getEOperations(), eClass.getEOperations(), diagnostics, context);
  }

  private class EOperationSignatureValidator
  {
    protected String messageKey;
    protected int messageCode;
    protected boolean ignoreOperationsWithSuppressedVisibility;

    public EOperationSignatureValidator(String messageKey, int messageCode)
    {
      this.messageKey = messageKey;
      this.messageCode = messageCode;
    }
    
    public EOperationSignatureValidator(String messageKey, int messageCode, boolean ignoreOperationsWithSuppressedVisibility)
    {
      this.messageKey = messageKey;
      this.messageCode = messageCode;
      this.ignoreOperationsWithSuppressedVisibility = ignoreOperationsWithSuppressedVisibility;
    }

    public final boolean validateEOperationSignatures
      (EClass eClass, EList<EOperation> eOperations, Collection<EOperation> otherEOperations, DiagnosticChain diagnostics, Map<Object, Object> context)
    {
      boolean result = true;
      for (EOperation eOperation : eOperations)
      {
        if (!ignoreOperationsWithSuppressedVisibility || !EcoreUtil.isSuppressedVisibility(eOperation))
        {
          String name = eOperation.getName();
          if (name != null)
          {
            EList<EParameter> eParameters = eOperation.getEParameters();
            int eParameterSize = eParameters.size();
            LOOP:
            for (EOperation otherEOperation : otherEOperations)
            {
              // Match against every other operation but this one.
              //
              if (otherEOperation == eOperation)
              {
                break;
              }
              else
              {
                String otherName = otherEOperation.getName();
                if (name.equals(otherName))
                {
                  EList<EParameter> otherEParmeters = otherEOperation.getEParameters();
                  if (otherEParmeters.size() == eParameterSize)
                  {
                    for (int i = 0; i < eParameterSize; ++i)
                    {
                      EParameter eParameter = eParameters.get(i);
                      EParameter otherEParameter = otherEParmeters.get(i);
                      EClassifier eType = eParameter.getEType();
                      EClassifier otherEType = otherEParameter.getEType();
  
                      // There is no match if the types are different
                      // and they don't each specify the same non-null instance class name.
                      //
                      if (eType != otherEType)
                      {
                        if (eType != null && otherEType != null)
                        {
                          String instanceClassName = eType.getInstanceClassName();
                          String otherInstanceClassName = otherEType.getInstanceClassName();
                          if (instanceClassName != otherInstanceClassName || instanceClassName == null || eParameter.isMany() != otherEParameter.isMany())
                          {
                            continue LOOP;
                          }
                        }
                        else
                        {
                          continue LOOP;
                        }
                      }
                      else if (eParameter.isMany() != otherEParameter.isMany())
                      {
                        continue LOOP;
                      }
                    }
                    if (diagnostics == null)
                    {
                      return false;
                    }
                    else
                    {
                      result = false;
  
                      EModelElement target = getTarget(otherEOperation);
                      diagnostics.add
                        (createDiagnostic
                          (Diagnostic.ERROR,
                           DIAGNOSTIC_SOURCE,
                           messageCode,
                           messageKey,
                           messageCode == DISJOINT_FEATURE_AND_OPERATION_SIGNATURES ? 
                             new Object[] { getObjectLabel(eOperation, context), getObjectLabel(target, context) } :
                             new Object[] { getObjectLabel(target, context), getObjectLabel(eOperation, context) },
                           messageCode == DISJOINT_FEATURE_AND_OPERATION_SIGNATURES ? 
                             new Object[] { eClass, eOperation, target, EcorePackage.Literals.ECLASS__EALL_OPERATIONS } :
                             new Object[] { eClass, target, eOperation, EcorePackage.Literals.ECLASS__EALL_OPERATIONS },
                           context));
                    }
                  }
                }
              }
            }
          }
        }
      }
      return result;
    }
      
    protected EModelElement getTarget(EOperation targetEOperation)
    {
      return targetEOperation;
    }
  }
  
  private final EOperationSignatureValidator uniqueOperationSignaturesValidator =
    new EOperationSignatureValidator("_UI_EClassUniqueEOperationSignatures_diagnostic", UNIQUE_OPERATION_SIGNATURES);

  /**
   * There are other constraints we should check such as consistency of the return type, 
   * correctness of the signature with respect to type substitution,
   * and so on...
   * Validates the UniqueOperationSignatures constraint of '<em>EClass</em>'.
   * <!-- begin-user-doc -->
   * No two operation defined in the same class may have matching signatures.
   * The signature is determined by the name of the operation and the types of its parameters.
   * If the name is the same and the types match, the signatures match.
   * Types match if they are same classifier, of both classifiers have instance class names that are the same.
   * <!-- end-user-doc -->
   * @generated NOT YET
   */
  @SuppressWarnings("unused")
  private boolean validateEClass_UniqueOperationSignatures2(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    EList<EOperation> eAllOperations = eClass.getEAllOperations();
    if (!eAllOperations.isEmpty())
    {
      // Iterate over all the operations but skip all the operations in the first super.
      //
      List<EOperation> eOperations = eAllOperations;
      EList<EClass> eSuperTypes = eClass.getESuperTypes();
      if (!eSuperTypes.isEmpty())
      {
        eOperations = eAllOperations.subList(eSuperTypes.get(0).getEAllOperations().size(), eAllOperations.size());
      }
      for (EOperation eOperation : eOperations)
      {
        String name = eOperation.getName();
        if (name != null)
        {
          EList<EParameter> eParameters = eOperation.getEParameters();
          int eParameterSize = eParameters.size();
          LOOP:
          for (EOperation otherEOperation : eAllOperations)
          {
            // Match against every other operation but this one.
            //
            if (otherEOperation == eOperation)
            {
              break;
            }
            else
            {
              String otherName = otherEOperation.getName();
              if (name.equals(otherName))
              {
                EList<EParameter> otherEParmeters = otherEOperation.getEParameters();
                if (otherEParmeters.size() == eParameterSize)
                {
                  for (int i = 0; i < eParameterSize; ++i)
                  {
                    EParameter eParameter = eParameters.get(i);
                    EParameter otherEParameter = otherEParmeters.get(i);
                    EClassifier eType = eParameter.getEType();
                    EClassifier otherEType = otherEParameter.getEType();

                    // There is no match if the types are different
                    // and they don't each specify the same non-null instance class name.
                    //
                    if (eType != otherEType)
                    {
                      if (eType != null && otherEType != null)
                      {
                        String instanceClassName = eType.getInstanceClassName();
                        String otherInstanceClassName = otherEType.getInstanceClassName();
                        if (instanceClassName != otherInstanceClassName && instanceClassName != null && otherInstanceClassName != null)
                        {
                          continue LOOP;
                        }
                      }
                    }
                  }
                  if (diagnostics == null)
                  {
                    return false;
                  }
                  else
                  {
                    result = false;

                    // We do not want to diagnose any error that have already been diagnosed by a super type.
                    //
                    for (EClass eSuperType : eClass.getEAllSuperTypes())
                    {
                      EList<EOperation> superTypeEAllOperations = eSuperType.getEAllOperations();
                      if (superTypeEAllOperations.contains(eOperation) && superTypeEAllOperations.contains(otherEOperation))
                      {
                        continue LOOP;
                      }
                    }

                    diagnostics.add
                      (createDiagnostic
                        (Diagnostic.ERROR,
                         DIAGNOSTIC_SOURCE,
                         UNIQUE_OPERATION_SIGNATURES,
                         "_UI_EClassUniqueEOperationSignatures_diagnostic",
                         new Object[] { getObjectLabel(eOperation, context), getObjectLabel(otherEOperation, context) },
                         new Object[] { eClass, eOperation, otherEOperation, EcorePackage.Literals.ECLASS__EALL_OPERATIONS },
                         context));
                  }
                }
              }
            }
          }
        }
      }
    }
    return result;
  }

  /**
   * Validates the NoCircularSuperTypes constraint of '<em>EClass</em>'.
   * <!-- begin-user-doc -->
   * A super type must not appear in its own list of all super types.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClass_NoCircularSuperTypes(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    EList<EClass> eAllSuperTypes = eClass.getEAllSuperTypes();
    boolean result = !eAllSuperTypes.contains(eClass);
    if (result)
    {
      for (EClass otherEClass : eAllSuperTypes)
      {
        if (otherEClass.getEAllSuperTypes().contains(eClass))
        {
          result = false;
          break;
        }
      }
    }
    if (!result && diagnostics != null)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           NO_CIRCULAR_SUPER_TYPES,
           "_UI_EClassNoCircularSuperTypes_diagnostic",
           null,
           new Object[] { eClass, EcorePackage.Literals.ECLASS__EALL_SUPER_TYPES },
           context));
    }
    return result;
  }

  /**
   * Validates the WellFormedMapEntryClass constraint of '<em>EClass</em>'.
   * <!-- begin-user-doc -->
   * A map entry class must have features named 'key' and 'value'.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClass_WellFormedMapEntryClass(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    if (eClass.getInstanceClassName() == "java.util.Map$Entry")
    {
      EStructuralFeature keyFeature = eClass.getEStructuralFeature("key");
      if (keyFeature == null)
      {
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               WELL_FORMED_MAP_ENTRY_CLASS,
               "_UI_EClassNotWellFormedMapEntry_diagnostic",
               new Object[] { "key" },
               new Object[] { eClass, EcorePackage.Literals.ECLASS__EALL_STRUCTURAL_FEATURES },
               context));
        }
      }
      EStructuralFeature valueFeature = eClass.getEStructuralFeature("value");
      if (valueFeature == null)
      {
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               WELL_FORMED_MAP_ENTRY_CLASS,
               "_UI_EClassNotWellFormedMapEntry_diagnostic", 
               new Object[] { "value" },
               new Object[] { eClass, EcorePackage.Literals.ECLASS__EALL_STRUCTURAL_FEATURES },
               context));
        }
      }
    }
    else
    {
      for (EClass eSuperType : eClass.getEAllSuperTypes())
      {
        if (eSuperType.getInstanceClassName() == "java.util.Map$Entry")
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            diagnostics.add
              (createDiagnostic
                (Diagnostic.ERROR,
                 DIAGNOSTIC_SOURCE,
                 WELL_FORMED_MAP_ENTRY_NO_INSTANCE_CLASS_NAME,
                 "_UI_EClassNotWellFormedMapEntryNoInstanceClassName_diagnostic",
                 null,
                 new Object[] { eClass, EcorePackage.Literals.ECLASSIFIER__INSTANCE_TYPE_NAME },
                 context));
          }
        }
      }
    }
    return result;
  }

  /**
   * Validates the ConsistentSuperTypes constraint of '<em>EClass</em>'.
   * <!-- begin-user-doc -->
   * The same class must not occur more than once among the generic super types
   * nor among all the generic super types
   * where occurrences in the latter represent conflicting instantiations of the same classifier.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClass_ConsistentSuperTypes(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;

    // Maintain a list of classifiers for looking up conflicts.
    //
    ArrayList<EClassifier> superTypes = new ArrayList<EClassifier>();

    // Look for duplicates among the generic super types.
    //
    EList<EGenericType> eGenericSuperTypes = eClass.getEGenericSuperTypes();
    for (EGenericType eGenericSuperType : eGenericSuperTypes)
    {
      // Ignore it if it isn't a class. Not being a class is diagnosed for the generic type itself.
      //
      EClassifier eClassifier = eGenericSuperType.getEClassifier();
      if (eClassifier instanceof EClass)
      {
        int index = superTypes.indexOf(eClassifier);
        if (index != -1)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            diagnostics.add
              (createDiagnostic
                (Diagnostic.ERROR,
                 DIAGNOSTIC_SOURCE,
                 CONSISTENT_SUPER_TYPES_DUPLICATE,
                 "_UI_EClassNoDuplicateSuperTypes_diagnostic",
                 new Object [] { eGenericSuperTypes.indexOf(eGenericSuperType), index },
                 new Object[] { eClass, eGenericSuperTypes.get(index), eGenericSuperType, EcorePackage.Literals.ECLASS__EGENERIC_SUPER_TYPES },
                 context));
          }
        }
      }
      superTypes.add(eClassifier);
    }

    if (result)
    {
      superTypes.clear();
      EList<EGenericType> eAllGenericSuperTypes = eClass.getEAllGenericSuperTypes();
      for (EGenericType eGenericSuperType : eAllGenericSuperTypes)
      {
        EClassifier eClassifier = eGenericSuperType.getEClassifier();
        if (eClassifier instanceof EClass)
        {
          int index = superTypes.indexOf(eClassifier);
          if (index != -1)
          {
            if (diagnostics == null)
            {
              return false;
            }
            else
            {
              result = false;
              diagnostics.add
                (createDiagnostic
                  (Diagnostic.ERROR,
                   DIAGNOSTIC_SOURCE,
                   CONSISTENT_SUPER_TYPES_CONFLICT,
                   "_UI_EClassConsistentSuperTypes_diagnostic",
                   new Object [] { getObjectLabel(eClassifier, context) },
                   new Object[] { eClass, eGenericSuperType,  eAllGenericSuperTypes.get(index), EcorePackage.Literals.ECLASS__EALL_GENERIC_SUPER_TYPES },
                   context));
            }
          }
        }
        superTypes.add(eClassifier);
      }
    }
    return result;
  }

  /**
   * Validates the DisjointFeatureAndOperationSignatures constraint of '<em>EClass</em>'.
   * <!-- begin-user-doc -->
   * Each feature defined in the class is 
   * interpreted as implicitly defining the operations 
   * with the signatures corresponding to the generated accessors for that feature
   * hence the same type of constraint as {@link #validateEClass_UniqueOperationSignatures(EClass, DiagnosticChain, Map)} applies.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClass_DisjointFeatureAndOperationSignatures(EClass eClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    EList<EOperation> eOperations = eClass.getEOperations();
    final Map<EOperation, EStructuralFeature> implicitEOperationToEStructuralFeatureMap = new LinkedHashMap<EOperation, EStructuralFeature>();
    if (!eOperations.isEmpty())
    {
      for (EStructuralFeature eStructuralFeature : eClass.getEStructuralFeatures())
      {
        String featureName = eStructuralFeature.getName();
        EClassifier eType = eStructuralFeature.getEType();
        if (featureName != null && featureName.length() != 0 && eType != null)
        {
          featureName = featureName.substring(0,1).toUpperCase() + featureName.substring(1);
          if (!EcoreUtil.isSuppressedVisibility(eStructuralFeature, EcoreUtil.GET))
          {
            String getAccessor = (eStructuralFeature.isMany() || !"boolean".equals(eType.getInstanceClassName()) ? "get" : "is") + featureName;
            if ("getClass".equals(getAccessor))
            {
              getAccessor = "getClass_";
            }
            EOperation eOperation = EcoreFactory.eINSTANCE.createEOperation();
            eOperation.setName(getAccessor);
            eOperation.setUpperBound(eStructuralFeature.getUpperBound());
            eOperation.setOrdered(eStructuralFeature.isOrdered());
            eOperation.setUnique(eStructuralFeature.isUnique());
            eOperation.setEType(eType);
            implicitEOperationToEStructuralFeatureMap.put(eOperation, eStructuralFeature);
          }
          if (!eStructuralFeature.isMany() && eStructuralFeature.isChangeable() && !EcoreUtil.isSuppressedVisibility(eStructuralFeature, EcoreUtil.SET))
          {
            String setAccessor = "set" + featureName;
            EOperation eOperation = EcoreFactory.eINSTANCE.createEOperation();
            eOperation.setName(setAccessor);
            EParameter eParameter = EcoreFactory.eINSTANCE.createEParameter();
            eParameter.setName(featureName);
            eParameter.setEType(eType);
            eOperation.getEParameters().add(eParameter);
            implicitEOperationToEStructuralFeatureMap.put(eOperation, eStructuralFeature);
          }
          if (eStructuralFeature.isUnsettable())
          {
            if (!EcoreUtil.isSuppressedVisibility(eStructuralFeature, EcoreUtil.IS_SET))
            {
              String isSetAccessor =  "isSet" + featureName;
              EOperation eOperation = EcoreFactory.eINSTANCE.createEOperation();
              eOperation.setName(isSetAccessor);
              eOperation.setEType(EcorePackage.Literals.EBOOLEAN);
              implicitEOperationToEStructuralFeatureMap.put(eOperation, eStructuralFeature);
            }
            if (!EcoreUtil.isSuppressedVisibility(eStructuralFeature, EcoreUtil.UNSET))
            {
              String unsetAccessor =  "unset" + featureName;
              EOperation eOperation = EcoreFactory.eINSTANCE.createEOperation();
              eOperation.setName(unsetAccessor);
              implicitEOperationToEStructuralFeatureMap.put(eOperation, eStructuralFeature);
            }
          }
        }
      }

      result =
        new EOperationSignatureValidator("_UI_EClassDisjointFeatureAndOperationSignatures_diagnostic", DISJOINT_FEATURE_AND_OPERATION_SIGNATURES, true)
        {
          @Override
          protected EModelElement getTarget(EOperation otherEOperation)
          {
            return implicitEOperationToEStructuralFeatureMap.get(otherEOperation);
          }
        }.validateEOperationSignatures(eClass, eOperations, implicitEOperationToEStructuralFeatureMap.keySet(), diagnostics, context);
    }
    return result;
  }
 
  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEClassifier(EClassifier eClassifier, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eClassifier, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClassifier_WellFormedInstanceTypeName(eClassifier, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClassifier_UniqueTypeParameterNames(eClassifier, diagnostics, context);
    return result;
  }

  /**
   * Validates the WellFormedInstanceTypeName constraint of '<em>EClassifier</em>'.
   * <!-- begin-user-doc -->
   * The instance type name may be null only for a class or an enum
   * must be {@link EGenericTypeBuilder#parseInstanceTypeName(String) well formed} when not null,
   * and must not specify type arguments if the classifier specifies type parameters.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClassifier_WellFormedInstanceTypeName(EClassifier eClassifier, DiagnosticChain diagnostics, final Map<Object, Object> context)
  {
    String instanceTypeName = eClassifier.getInstanceTypeName();
    Diagnostic typeBuilderDiagnostic = 
      instanceTypeName == null ? 
        null : 
        new EGenericTypeBuilder()
        {
          @Override
          protected BasicDiagnostic createDiagnostic(int severity, String source, int code, String messageKey, Object[] messageSubstitutions, Object[] data)
          {
            return EcoreValidator.this.createDiagnostic(severity, source, code, messageKey, messageSubstitutions, data, context);
          }

          @Override
          protected ResourceLocator getResourceLocator()
          {
            return EcoreValidator.this.getResourceLocator();
          }

          @Override
          protected String getString(String key, Object[] substitutions)
          {
            return EcoreValidator.this.getString(key, substitutions);
          }

          @Override
          protected void report(DiagnosticChain diagnostics, String key, Object[] substitutions, int index)
          {
            EcoreValidator.this.report(diagnostics, key, substitutions, index, context);
          }
        }.parseInstanceTypeName(instanceTypeName);
    String formattedName = null;
    boolean result =
      instanceTypeName != null ?
        typeBuilderDiagnostic.getSeverity() == Diagnostic.OK  && 
          instanceTypeName.equals(formattedName = EcoreUtil.toJavaInstanceTypeName((EGenericType)typeBuilderDiagnostic.getData().get(0))) :
        eClassifier instanceof EClass || eClassifier instanceof EEnum;
    if (!result && diagnostics != null)
    {
      BasicDiagnostic diagnosic =
        createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           WELL_FORMED_INSTANCE_TYPE_NAME,
           "_UI_EClassifierInstanceTypeNameNotWellFormed_diagnostic",
           new Object[] { getValueLabel(EcorePackage.Literals.ESTRING, instanceTypeName, context) },
           new Object[] { eClassifier, EcorePackage.Literals.ECLASSIFIER__INSTANCE_TYPE_NAME },
           context);
      if (typeBuilderDiagnostic != null)
      {
        if (!typeBuilderDiagnostic.getChildren().isEmpty())
        {
          diagnosic.addAll(typeBuilderDiagnostic);
        }
        else if (instanceTypeName != null && formattedName != null)
        {
          // The string must contain inappropriate whitespace, so find the index for the first difference.
          //
          int i = 0;
          for (int length = Math.min(instanceTypeName.length(), formattedName.length()); 
               i < length; 
               i = Character.offsetByCodePoints(instanceTypeName, i, 1))
          {
            if (instanceTypeName.codePointAt(i) != formattedName.codePointAt(i))
            {
              break;
            }
          }
          
          diagnosic.add
           (createDiagnostic
             (Diagnostic.ERROR,
              DIAGNOSTIC_SOURCE,
              WELL_FORMED_INSTANCE_TYPE_NAME,
              instanceTypeName.codePointAt(i) == ' ' ? "_UI_EClassifierInstanceTypeNameUnexpectedSpace_diagnostic" : "_UI_EClassifierInstanceTypeNameExpectedSpace_diagnostic",
              new Object[] { i },
              new Object[] { i },
              context));
        }
      }
      diagnostics.add(diagnosic);
    }
    if (result && instanceTypeName != null && instanceTypeName.indexOf('<') != -1 && eClassifier.getETypeParameters().size() != 0)
    {
      result = false;
      if (diagnostics != null)
      {
        diagnostics.add
          (createDiagnostic
            (Diagnostic.ERROR,
             DIAGNOSTIC_SOURCE,
             WELL_FORMED_INSTANCE_TYPE_NAME,
             "_UI_EClassifierInstanceTypeNameUnexpectedTypeArguments_diagnostic",
             null,
             new Object[] { eClassifier, EcorePackage.Literals.ECLASSIFIER__INSTANCE_TYPE_NAME },
             context));
      }
    }

    return result;
  }

  /**
   * Validates the UniqueTypeParameterNames constraint of '<em>EClassifier</em>'.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEClassifier_UniqueTypeParameterNames(EClassifier eClassifier, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    Map<String, List<ETypeParameter>> keys = new HashMap<String, List<ETypeParameter>>();
    for (ETypeParameter eTypeParameter : eClassifier.getETypeParameters())
    {
      String name = eTypeParameter.getName();
      if (name != null)
      {
        List<ETypeParameter> eTypeParameters = keys.get(name);
        if (eTypeParameters == null)
        {
          eTypeParameters = new ArrayList<ETypeParameter>();
          keys.put(name, eTypeParameters);
        }
        eTypeParameters.add(eTypeParameter);
        if (eTypeParameters.size() > 1)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
          }
        }
      }
    }

    if (!result && diagnostics != null)
    {
      for (Map.Entry<String, List<ETypeParameter>> entry : keys.entrySet())
      {
        List<ETypeParameter> eTypeParameters = entry.getValue();
        if (eTypeParameters.size() > 1)
        {
          List<Object> objects = new ArrayList<Object>();
          objects.add(eClassifier);
          for (ETypeParameter eTypeParameter : eTypeParameters)
          {
            objects.add(eTypeParameter);
          }
          objects.add(EcorePackage.Literals.ECLASSIFIER__ETYPE_PARAMETERS );
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               UNIQUE_TYPE_PARAMETER_NAMES,
               "_UI_UniqueTypeParameterNames_diagnostic", 
               new Object[] { entry.getKey() },
               objects.toArray(new Object[objects.size()]),
               context));
          
        }
      }
      
    }
    return result;
  }
  
  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEDataType(EDataType eDataType, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eDataType, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClassifier_WellFormedInstanceTypeName(eDataType, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClassifier_UniqueTypeParameterNames(eDataType, diagnostics, context);
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEEnum(EEnum eEnum, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eEnum, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClassifier_WellFormedInstanceTypeName(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validateEClassifier_UniqueTypeParameterNames(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validateEEnum_UniqueEnumeratorNames(eEnum, diagnostics, context);
    if (result || diagnostics != null) result &= validateEEnum_UniqueEnumeratorLiterals(eEnum, diagnostics, context);
    return result;
  }

  /**
   * Validates the UniqueEnumeratorNames constraint of '<em>EEnum</em>'.
   * <!-- begin-user-doc -->
   * No two enum literals may have matching names.
   * Literal names are matched ignoring their case and their underscore separators.
   * It is an error to have two enum literals with names that are equal but only a warning to have two enum literals with names that match.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEEnum_UniqueEnumeratorNames(EEnum eEnum, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    EList<EEnumLiteral> eLiterals = eEnum.getELiterals();
    Map<String, List<EEnumLiteral>> keys = new HashMap<String, List<EEnumLiteral>>();
    for (EEnumLiteral eEnumLiteral : eLiterals)
    {
      String name = eEnumLiteral.getName();
      if (name != null)
      {
        String key = name.replace("_", "").toUpperCase();
        List<EEnumLiteral> eEnumLiterals = keys.get(key);
        if (eEnumLiterals == null)
        {
          eEnumLiterals = new ArrayList<EEnumLiteral>();
          keys.put(key, eEnumLiterals);
        }
        eEnumLiterals.add(eEnumLiteral);
        if (eEnumLiterals.size() > 1)
        {
          if (diagnostics == null)
          {
           return false;
          }
          else
          {
            result = false;
          }
        }
      }
    }

    if (!result && diagnostics != null)
    {
      for (Map.Entry<String, List<EEnumLiteral>> entry : keys.entrySet())
      {
        List<EEnumLiteral> eEnumLiterals = entry.getValue();
        if (eEnumLiterals.size() > 1)
        {
          List<String> names = new UniqueEList<String>();
          List<Object> objects = new ArrayList<Object>();
          objects.add(eEnum);
          for (EEnumLiteral eEnumLiteral : eEnumLiterals)
          {
            names.add(eEnumLiteral.getName());
            objects.add(eEnumLiteral);
          }
          objects.add(EcorePackage.Literals.EENUM__ELITERALS);
  
          if (names.size() == objects.size() - 2)
          {
            diagnostics.add
              (createDiagnostic
                (Diagnostic.WARNING,
                 DIAGNOSTIC_SOURCE,
                 UNIQUE_ENUMERATOR_NAMES,
                 "_UI_EEnumDissimilarEnumeratorNames_diagnostic",
                 names.toArray(new Object[names.size()]),
                 objects.toArray(new Object[objects.size()]),
                 context));
            
          }
          else
          {
            diagnostics.add
              (createDiagnostic
                (Diagnostic.ERROR,
                 DIAGNOSTIC_SOURCE,
                 UNIQUE_ENUMERATOR_NAMES,
                 "_UI_EEnumUniqueEnumeratorNames_diagnostic",
                 new Object [] { names.get(0) },
                 objects.toArray(new Object[objects.size()]),
                 context));
          }
        }
      }
    }
    return result;
  }

  /**
   * Validates the UniqueEnumeratorLiterals constraint of '<em>EEnum</em>'.
   * <!-- begin-user-doc -->
   * No two enum literals may have the same literal value.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEEnum_UniqueEnumeratorLiterals(EEnum eEnum, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    EList<EEnumLiteral> eLiterals = eEnum.getELiterals();
    Map<String, List<EEnumLiteral>> keys = new HashMap<String, List<EEnumLiteral>>();
    for (EEnumLiteral eEnumLiteral : eLiterals)
    {
      String literal = eEnumLiteral.getLiteral();
      if (literal != null)
      {
        List<EEnumLiteral> eEnumLiterals = keys.get(literal);
        if (eEnumLiterals == null)
        {
          eEnumLiterals = new ArrayList<EEnumLiteral>();
          keys.put(literal, eEnumLiterals);
        }
        eEnumLiterals.add(eEnumLiteral);

        if (eEnumLiterals.size() > 1)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            EEnumLiteral otherEEnumLiteral = eEnumLiterals.get(0);
            // Don't complain about the literals if they are the same as the names and the names collide.
            //
            String name = eEnumLiteral.getName();
            if (name != null && name.equals(literal) & name.equals(otherEEnumLiteral.getName()))
            {
              eEnumLiterals.remove(eEnumLiteral);
            }
          }
        }
      }
    }

    if (!result && diagnostics != null)
    {
      for (Map.Entry<String, List<EEnumLiteral>> entry : keys.entrySet())
      {
        List<EEnumLiteral> eEnumLiterals = entry.getValue();
        if (eEnumLiterals.size() > 1)
        {
          List<Object> objects = new ArrayList<Object>();
          objects.add(eEnum);
          for (EEnumLiteral eEnumLiteral : eEnumLiterals)
          {
            objects.add(eEnumLiteral);
          }
          objects.add(EcorePackage.Literals.EENUM__ELITERALS);
  
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               UNIQUE_ENUMERATOR_LITERALS,
               "_UI_EEnumUniqueEnumeratorLiterals_diagnostic", 
               new Object[] { entry.getKey() },
               objects.toArray(new Object[objects.size()]),
               context));
        }
      }
    }
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEEnumLiteral(EEnumLiteral eEnumLiteral, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eEnumLiteral, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eEnumLiteral, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eEnumLiteral, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eEnumLiteral, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eEnumLiteral, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eEnumLiteral, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eEnumLiteral, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eEnumLiteral, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eEnumLiteral, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eEnumLiteral, diagnostics, context);
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEFactory(EFactory eFactory, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return validate_EveryDefaultConstraint(eFactory, diagnostics, context);
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEModelElement(EModelElement eModelElement, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return validate_EveryDefaultConstraint(eModelElement, diagnostics, context);
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateENamedElement(ENamedElement eNamedElement, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eNamedElement, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eNamedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eNamedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eNamedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eNamedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eNamedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eNamedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eNamedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eNamedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eNamedElement, diagnostics, context);
    return result;
  }

  /**
   * Validates the WellFormedName constraint of '<em>ENamed Element</em>'.
   * <!-- begin-user-doc -->
   * The name must be a valid Java identifier.
   * I.e., it must start with a {@link Character#isJavaIdentifierStart(int) Java identifier start character},
   * that is followed by zero or more {@link Character#isJavaIdentifierPart(int) Java identifier part characters}.
   * This constraint is only enforced in a {@link #STRICT_NAMED_ELEMENT_NAMES} context.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateENamedElement_WellFormedName(ENamedElement eNamedElement, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (context != null && Boolean.FALSE.equals(context.get(STRICT_NAMED_ELEMENT_NAMES)))
    {
      return true;
    }

    String name = eNamedElement.getName();
    boolean result = isWellFormedJavaIdentifier(name);
    if (!result && diagnostics != null)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           WELL_FORMED_NAME,
           "_UI_ENamedElementNameNotWellFormed_diagnostic",
           new Object[] { getValueLabel(EcorePackage.Literals.ESTRING, name, context) },
           new Object[] { eNamedElement, EcorePackage.Literals.ENAMED_ELEMENT__NAME },
           context));
    }
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEObject(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return validate_EveryDefaultConstraint(eObject, diagnostics, context);
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEOperation(EOperation eOperation, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eOperation, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidLowerBound(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidUpperBound(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ConsistentBounds(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidType(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validateEOperation_UniqueParameterNames(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validateEOperation_UniqueTypeParameterNames(eOperation, diagnostics, context);
    if (result || diagnostics != null) result &= validateEOperation_NoRepeatingVoid(eOperation, diagnostics, context);
    return result;
  }

  /**
   * Validates the UniqueParameterNames constraint of '<em>EOperation</em>'.
   * <!-- begin-user-doc -->
   * No two parameters may have the same name.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEOperation_UniqueParameterNames(EOperation eOperation, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    Map<String, List<EParameter>> keys = new HashMap<String, List<EParameter>>();
    for (EParameter eParameter : eOperation.getEParameters())
    {
      String name = eParameter.getName();
      if (name != null)
      {
        List<EParameter> eParameters = keys.get(name);
        if (eParameters == null)
        {
          eParameters = new ArrayList<EParameter>();
          keys.put(name, eParameters);
        }
        eParameters.add(eParameter);
        if (eParameters.size() > 1)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
          }
        }
      }
    }

    if (!result && diagnostics != null)
    {
      for (Map.Entry<String, List<EParameter>> entry : keys.entrySet())
      {
        List<EParameter> eParameters = entry.getValue();
        if (eParameters.size() > 1)
        {
          List<Object> objects = new ArrayList<Object>();
          objects.add(eOperation);
          for (EParameter eParameter : eParameters)
          {
            objects.add(eParameter);
          }
          objects.add(EcorePackage.Literals.EOPERATION__EPARAMETERS);
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               UNIQUE_PARAMETER_NAMES,
               "_UI_EOperationUniqueParameterNames_diagnostic", 
               new Object[] { entry.getKey() },
               objects.toArray(new Object[objects.size()]),
               context));
        }
      } 
    }
    return result;
  }

  /**
   * Validates the UniqueTypeParameterNames constraint of '<em>EOperation</em>'.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEOperation_UniqueTypeParameterNames(EOperation eOperation, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    Map<String, List<ETypeParameter>> keys = new HashMap<String, List<ETypeParameter>>();
    for (ETypeParameter eTypeParameter : eOperation.getETypeParameters())
    {
      String name = eTypeParameter.getName();
      if (name != null)
      {
        List<ETypeParameter> eTypeParameters = keys.get(name);
        if (eTypeParameters == null)
        {
          eTypeParameters = new ArrayList<ETypeParameter>();
          keys.put(name, eTypeParameters);
        }
        eTypeParameters.add(eTypeParameter);
        if (eTypeParameters.size() > 1)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
          }
        }
      }
    }

    if (!result && diagnostics != null)
    {
      for (Map.Entry<String, List<ETypeParameter>> entry : keys.entrySet())
      {
        List<ETypeParameter> eTypeParameters = entry.getValue();
        if (eTypeParameters.size() > 1)
        {
          List<Object> objects = new ArrayList<Object>();
          objects.add(eOperation);
          for (ETypeParameter eTypeParameter : eTypeParameters)
          {
            objects.add(eTypeParameter);
          }
          objects.add(EcorePackage.Literals.EOPERATION__ETYPE_PARAMETERS );
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               UNIQUE_TYPE_PARAMETER_NAMES,
               "_UI_UniqueTypeParameterNames_diagnostic", 
               new Object[] { entry.getKey() },
               objects.toArray(new Object[objects.size()]),
               context));
          
        }
      }
      
    }
    return result;
  }

  /**
   * Validates the NoRepeatingVoid constraint of '<em>EOperation</em>'.
   * <!-- begin-user-doc -->
   * An operation without a type, which represents void, must have an upper bound of 1.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEOperation_NoRepeatingVoid(EOperation eOperation, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    int upperBound = eOperation.getUpperBound();
    boolean result = upperBound == 1 || eOperation.getEType() != null;
    if (!result && diagnostics != null)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           NO_REPEATING_VOID,
           "_UI_EOperationNoRepeatingVoid_diagnostic", 
           new Object [] { upperBound },
           new Object[] { eOperation, EcorePackage.Literals.ETYPED_ELEMENT__UPPER_BOUND },
           context));
    }
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEPackage(EPackage ePackage, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(ePackage, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validateEPackage_WellFormedNsURI(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validateEPackage_WellFormedNsPrefix(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validateEPackage_UniqueSubpackageNames(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validateEPackage_UniqueClassifierNames(ePackage, diagnostics, context);
    if (result || diagnostics != null) result &= validateEPackage_UniqueNsURIs(ePackage, diagnostics, context);
    return result;
  }

  /**
   * Validates the WellFormedNsURI constraint of '<em>EPackage</em>'.
   * <!-- begin-user-doc -->
   * The namespace URI must be {@link #isWellFormedURI(String) well formed} and may not be <code>null</code>.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEPackage_WellFormedNsURI(EPackage ePackage, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    String nsURI = ePackage.getNsURI();
    boolean result = isWellFormedURI(nsURI);
    if (!result && diagnostics != null)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           WELL_FORMED_NS_URI,
           "_UI_EPackageNsURINotWellFormed_diagnostic",
           new Object[] { nsURI },
           new Object[] { ePackage, EcorePackage.Literals.EPACKAGE__NS_URI },
           context));
    }
    return result;
  }

  /**
   * Validates the WellFormedNsPrefix constraint of '<em>EPackage</em>'.
   * <!-- begin-user-doc -->
   * The namespace prefix must be either the empty string
   * or a {@link XMLTypeValidator#validateNCName(String, DiagnosticChain, Map) valid NCName}
   * that does not start with any case combination of the three letters
   * <a href="http://www.w3.org/TR/REC-xml-names/#xmlReserved">"xml"</a>.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEPackage_WellFormedNsPrefix(EPackage ePackage, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    String nsPrefix = ePackage.getNsPrefix();
    boolean
      result = "".equals(nsPrefix) ||
        nsPrefix != null &&
          XMLTypeValidator.INSTANCE.validateNCName(nsPrefix, null, context) &&
          (!nsPrefix.toLowerCase().startsWith("xml") || XMLNamespacePackage.eNS_URI.equals(ePackage.getNsURI()));
    if (!result && diagnostics != null)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           WELL_FORMED_NS_PREFIX,
           "_UI_EPackageNsPrefixNotWellFormed_diagnostic",
           new Object[] { nsPrefix },
           new Object[] { ePackage, EcorePackage.Literals.EPACKAGE__NS_PREFIX },
           context));
    }
    return result;
  }

  /**
   * Validates the UniqueSubpackageNames constraint of '<em>EPackage</em>'.
   * <!-- begin-user-doc -->
   * No two packages my have the same name.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEPackage_UniqueSubpackageNames(EPackage ePackage, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    Map<String, List<EPackage>> keys = new HashMap<String, List<EPackage>>();
    for (EPackage eSubpackage : ePackage.getESubpackages())
    {
      String name = eSubpackage.getName();
      if (name != null)
      {
        List<EPackage> eSubpackages = keys.get(name);
        if (eSubpackages == null)
        {
          eSubpackages = new ArrayList<EPackage>();
          keys.put(name,  eSubpackages);
        }
        eSubpackages.add(eSubpackage);
        if (eSubpackages.size() > 1)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
          }
        }
      }
    }
    
    if (!result && diagnostics != null)
    {
      for (Map.Entry<String, List<EPackage>> entry : keys.entrySet())
      {
        List<EPackage> eSubpackages = entry.getValue();
        if (eSubpackages.size() > 1)
        {
          List<Object> objects = new ArrayList<Object>();
          objects.add(ePackage);
          for (EPackage eSubpackage : eSubpackages)
          {
            objects.add(eSubpackage);
          }
          objects.add(EcorePackage.Literals.EPACKAGE__ESUBPACKAGES);
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               UNIQUE_SUBPACKAGE_NAMES,
               "_UI_EPackageUniqueSubpackageNames_diagnostic", 
               new Object[] { entry.getKey() },
               objects.toArray(new Object[objects.size()]),
               context));
        }
      }
    }
    return result;
  }

  /**
   * Validates the UniqueClassifierNames constraint of '<em>EPackage</em>'.
   * <!-- begin-user-doc -->
   * No two classifiers may have matching names.
   * Classifier names are matched ignoring their case and their underscore separators.
   * It is an error to have two classifier with names that are equal but only a warning to have two classifiers with names that match.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEPackage_UniqueClassifierNames(EPackage ePackage, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    Map<String, List<EClassifier>> keys = new HashMap<String, List<EClassifier>>();
    for (EClassifier eClassifier : ePackage.getEClassifiers())
    {
      String name = eClassifier.getName();

      // Don't bother complaining about things with no name,  since there are constraints for that problem.
      //
      if (name != null)
      {
        // Drop the _ separators and normalize the case.
        //
        String key = name.replace("_", "").toLowerCase();
        List<EClassifier> eClassifiers = keys.get(key);
        if (eClassifiers == null)
        {
          eClassifiers = new ArrayList<EClassifier>();
          keys.put(key, eClassifiers);
        }
        eClassifiers.add(eClassifier);

        if (eClassifiers.size() > 1)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
          }
        }
      }
    }

    if (!result && diagnostics != null)
    {
      for (Map.Entry<String, List<EClassifier>> entry : keys.entrySet())
      {
        List<EClassifier> eClassifiers = entry.getValue();
        if (eClassifiers.size() > 1)
        {
          List<String> names = new UniqueEList<String>();
          List<Object> objects = new ArrayList<Object>();
          objects.add(ePackage);
          for (EClassifier eClassifier : eClassifiers)
          {
            names.add(eClassifier.getName());
            objects.add(eClassifier);
          }
          objects.add(EcorePackage.Literals.EPACKAGE__ECLASSIFIERS);
            
          if (names.size() == objects.size() - 2)
          {
            diagnostics.add
              (createDiagnostic
                (Diagnostic.WARNING,
                 DIAGNOSTIC_SOURCE,
                 UNIQUE_CLASSIFIER_NAMES,
                 "_UI_EPackageDissimilarClassifierNames_diagnostic",
                 names.toArray(new Object[names.size()]),
                 objects.toArray(new Object[objects.size()]),
                 context));
              
          }
          else
          {
            diagnostics.add
              (createDiagnostic
                (Diagnostic.ERROR,
                 DIAGNOSTIC_SOURCE,
                 UNIQUE_CLASSIFIER_NAMES,
                 "_UI_EPackageUniqueClassifierNames_diagnostic",
                 new Object [] { names.get(0) },
                 objects.toArray(new Object[objects.size()]),
                 context));
          }
        }
      }
    }
    return result;
  }

  /**
   * Validates the UniqueNsURIs constraint of '<em>EPackage</em>'.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEPackage_UniqueNsURIs(EPackage ePackage, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    String nsURI = ePackage.getNsURI();
    if (nsURI != null)
    {
      EPackage rootEPackage = ePackage;
      for (EPackage eSuperPackage = ePackage.getESuperPackage(); eSuperPackage != null; eSuperPackage = eSuperPackage.getESuperPackage())
      {
        rootEPackage = eSuperPackage;
      }
      
      UniqueEList<EPackage> ePackages = new UniqueEList.FastCompare<EPackage>();
      ePackages.add(rootEPackage);
      for (int i = 0; i < ePackages.size(); ++i)
      {
        ePackages.addAll(ePackages.get(i).getESubpackages());
      }
      ePackages.remove(ePackage);

      for (EPackage otherEPackage : ePackages)
      {
        if (nsURI.equals(otherEPackage.getNsURI()))
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            diagnostics.add
              (createDiagnostic
                (Diagnostic.ERROR,
                 DIAGNOSTIC_SOURCE,
                 UNIQUE_NS_URIS,
                 "_UI_EPackageUniqueNsURIs_diagnostic", 
                 new Object[] { nsURI },
                 new Object[] { ePackage, otherEPackage, EcorePackage.Literals.EPACKAGE__ESUBPACKAGES },
                 context));
          }
        }
      }
    }
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEParameter(EParameter eParameter, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eParameter, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidLowerBound(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidUpperBound(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ConsistentBounds(eParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidType(eParameter, diagnostics, context);
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEReference(EReference eReference, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eReference, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidLowerBound(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidUpperBound(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ConsistentBounds(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidType(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateEStructuralFeature_ValidDefaultValueLiteral(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateEReference_ConsistentOpposite(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateEReference_SingleContainer(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateEReference_ConsistentKeys(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateEReference_ConsistentUnique(eReference, diagnostics, context);
    if (result || diagnostics != null) result &= validateEReference_ConsistentContainer(eReference, diagnostics, context);
    return result;
  }

  /**
   * Validates the ConsistentOpposite constraint of '<em>EReference</em>'.
   * <!-- begin-user-doc -->
   * An {@link EReference#getEOpposite() opposite} is optional but if one exists,
   * it must be a feature of this references's {@link EReference#getEReferenceType() type},
   * it must have this reference as its opposite,
   * and, if this feature is {@link EStructuralFeature#isTransient() transient},
   * then the opposite must also be transient,
   * must not {@link EReference#isResolveProxies() resolve proxies}.
   * or must be a {@link EReference#isContainment() containment},
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEReference_ConsistentOpposite(EReference eReference, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    EReference eOpposite = eReference.getEOpposite();
    if (eOpposite != null)
    {
      if (eReference.getEContainingClass() != null)
      {
        EReference oppositeEOpposite = eOpposite.getEOpposite();
        if (oppositeEOpposite != eReference)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            diagnostics.add
              (createDiagnostic
                (Diagnostic.ERROR,
                 DIAGNOSTIC_SOURCE,
                 CONSISTENT_OPPOSITE_NOT_MATCHING,
                 "_UI_EReferenceOppositeOfOppositeInconsistent_diagnostic",
                 null,
                 new Object[] { eReference, eOpposite, oppositeEOpposite, EcorePackage.Literals.EREFERENCE__EOPPOSITE },
                 context));
          }
        }
        EClassifier eType = eReference.getEType();
        if (eType != null)
        {
          EClass oppositeEContainingClass = eOpposite.getEContainingClass();
          if (oppositeEContainingClass != null && oppositeEContainingClass != eType)
          {
            if (diagnostics == null)
            {
              return false;
            }
            else
            {
              result = false;
              diagnostics.add
                (createDiagnostic
                  (Diagnostic.ERROR,
                   DIAGNOSTIC_SOURCE,
                   CONSISTENT_OPPOSITE_NOT_FROM_TYPE,
                   "_UI_EReferenceOppositeNotFeatureOfType_diagnostic",
                   null,
                   new Object[] { eReference, eOpposite, eType, EcorePackage.Literals.EREFERENCE__EOPPOSITE },
                   context));
            }
          }
        }
      }
      if (result)
      {
        result = eReference != eOpposite;
        if (diagnostics != null && !result)
        {
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               CONSISTENT_OPPOSITE_BAD_TRANSIENT,
               "_UI_EReferenceSelfOpposite_diagnostic",
               null,
               new Object[] { eReference, eOpposite, EcorePackage.Literals.EREFERENCE__EOPPOSITE, EcorePackage.Literals.EREFERENCE__EOPPOSITE },
               context));
        }
      }
      if (result)
      {
        result =
          !isEffectivelyTransient(eReference) ||
            isEffectivelyTransient(eOpposite) ||
            !eOpposite.isResolveProxies() ||
            eOpposite.isContainment();
        if (diagnostics != null && !result)
        {
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               CONSISTENT_OPPOSITE_BAD_TRANSIENT,
               "_UI_EReferenceTransientOppositeNotTransient_diagnostic",
               null,
               new Object[] { eReference, eOpposite, EcorePackage.Literals.EREFERENCE__EOPPOSITE, EcorePackage.Literals.ESTRUCTURAL_FEATURE__TRANSIENT },
               context));
        }
      }
      if (result)
      {
        result = !eReference.isContainment() || !eOpposite.isContainment();
        if (diagnostics != null && !result)
        {
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               CONSISTENT_OPPOSITE_BOTH_CONTAINMENT,
               "_UI_EReferenceOppositeBothContainment_diagnostic",
               null,
               new Object[] { eReference, eOpposite, EcorePackage.Literals.EREFERENCE__EOPPOSITE, EcorePackage.Literals.EREFERENCE__CONTAINMENT },
               context));
        }
      }
    }
    return result;
  }

  /**
   * Validates the SingleContainer constraint of '<em>EReference</em>'.
   * <!-- begin-user-doc -->
   * A {@link EReference#isContainer() container} reference must have a upper bound of 1.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEReference_SingleContainer(EReference eReference, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = !eReference.isContainer() || eReference.getUpperBound() == 1;
    if (diagnostics != null && !result)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           SINGLE_CONTAINER,
           "_UI_EReferenceSingleContainer_diagnostic",
           new Object[] { eReference.getUpperBound() },
           new Object[] { eReference, EcorePackage.Literals.ETYPED_ELEMENT__UPPER_BOUND },
           context));
    }
    return result;
  }


  /**
   * Validates the ConsistentKeys constraint of '<em>EReference</em>'.
   * <!-- begin-user-doc -->
   * The {@link EReference#getEKeys() keys} of a reference must be features of the reference's {@link ETypedElement#getEType()}.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEReference_ConsistentKeys(EReference eReference, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    EList<EAttribute> eKeys = eReference.getEKeys();
    if (!eKeys.isEmpty())
    {
      EClass eClass = eReference.getEReferenceType();
      if (eClass != null)
      {
        for (EAttribute eAttribute :eKeys)
        {
          if (eClass.getFeatureID(eAttribute) == -1)
          {
            if (diagnostics == null)
            {
              return false;
            }
            else
            {
              result = false;
              diagnostics.add
                (createDiagnostic
                  (Diagnostic.ERROR,
                   DIAGNOSTIC_SOURCE,
                   CONSISTENT_KEYS,
                   "_UI_EReferenceConsistentKeys_diagnostic",
                   new Object[] { getObjectLabel(eAttribute, context) },
                   new Object[] { eReference, eAttribute, EcorePackage.Literals.EREFERENCE__EKEYS },
                   context));
            }
          }
        }
      }
    }
    return result;
  }

  /**
   * Validates the ConsistentUnique constraint of '<em>EReference</em>'.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEReference_ConsistentUnique(EReference eReference, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    // Multi-valued references that are containment or bidirectional must be unique.
    //
    boolean result = true;
    if (eReference.isMany() && 
          (eReference.isContainment() || eReference.getEOpposite() != null) &&
          !eReference.isUnique())
    {
      result = false;
      if (diagnostics != null)
      {
        diagnostics.add
          (createDiagnostic
            (Diagnostic.ERROR,
             DIAGNOSTIC_SOURCE,
             CONSISTENT_UNIQUE,
             "_UI_EReferenceConsistentUnique_diagnostic",
             null,
             new Object[] { eReference, EcorePackage.Literals.ETYPED_ELEMENT__UNIQUE },
             context));
      }
    }
    return result;
  }

  /**
   * Validates the ConsistentContainer constraint of '<em>EReference</em>'.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEReference_ConsistentContainer(EReference eReference, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (eReference.isContainment() && eReference.getEContainingClass() != null)
    {
      EClass eClass = eReference.getEReferenceType();
      if (eClass != null)
      {
        for (EReference otherEReference : eClass.getEAllReferences())
        {
          if (otherEReference.isRequired() && otherEReference.isContainer() && otherEReference.getEOpposite() != eReference)
          {
            if (diagnostics != null)
            {
              diagnostics.add
                (createDiagnostic
                  (Diagnostic.ERROR,
                   DIAGNOSTIC_SOURCE,
                   CONSISTENT_CONTAINER,
                   "_UI_EReferenceConsistentContainer_diagnostic",
                   new Object[] { getObjectLabel(otherEReference, context) },
                   new Object[] { eReference, otherEReference, EcorePackage.Literals.ETYPED_ELEMENT__LOWER_BOUND },
                   context));
            }
            return false;
          }
        }
      }
    }
    return true; 
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEStructuralFeature(EStructuralFeature eStructuralFeature, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eStructuralFeature, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidLowerBound(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidUpperBound(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ConsistentBounds(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidType(eStructuralFeature, diagnostics, context);
    if (result || diagnostics != null) result &= validateEStructuralFeature_ValidDefaultValueLiteral(eStructuralFeature, diagnostics, context);
    return result;
  }

  /**
   * Validates the ValidDefaultValueLiteral constraint of '<em>EStructural Feature</em>'.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEStructuralFeature_ValidDefaultValueLiteral(EStructuralFeature eStructuralFeature, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    String defaultValueLiteral = eStructuralFeature.getDefaultValueLiteral();
    Object defaultValue = null;
    EDataType eDataType = null;
    boolean result = true;
    boolean warning = false;
    if (defaultValueLiteral != null)
    {
      EClassifier eType = eStructuralFeature.getEType();
      if (eType instanceof EDataType)
      {
        eDataType = (EDataType)eType;
        defaultValue = eStructuralFeature.getDefaultValue();
        if (defaultValue == null)
        {
          // We need to be conservative and diagnose a problem only if we are quite sure that type is built-in 
          // and hence that the lack of a default value really represents a problem with being unable to convert the literal to a value dynamically,
          // not just a problem that the specialized factory conversion logic hasn't been generated yet.
          // 
          if (isBuiltinEDataType(eDataType))
          {
            result = false;
          }
          else
          {
            // If there is a conversion delegate then the lack of a default value really does indicate that there is a problem converting the literal to a value,
            // unless there is no instance class, in which case we mustn't be able to load the class and we can't expect the conversion delegate to function.
            //
            EDataType.Internal.ConversionDelegate conversionDelegate = ((EDataType.Internal)eDataType).getConversionDelegate();
            if (conversionDelegate != null && eDataType.getInstanceClass() != null)
            {
              result = false;
            }
            else
            {
              // If the data type is an enum or derives from an enum 
              // then it's unlikely there is ever specialized code for converting the value 
              // so probably the literal is bad and we should at least produce a warning.
              //
              EEnum eEnum = getEEnum(eDataType);
              if (eEnum != null)
              {
                result = false;
                warning = true;
              }
            }
          }
        }
        else
        {
          result = getRootEValidator(context).validate(eDataType, defaultValue, null, context);
        }
      }
      else
      {
        result = false;
      }
    }
    if (diagnostics != null && !result)
    {
      BasicDiagnostic diagnostic =
        createDiagnostic
         (warning? Diagnostic.WARNING : Diagnostic.ERROR,
          DIAGNOSTIC_SOURCE,
          VALID_DEFAULT_VALUE_LITERAL,
          "_UI_EStructuralFeatureValidDefaultValueLiteral_diagnostic",
          new Object[] { defaultValueLiteral },
          new Object[] { eStructuralFeature, EcorePackage.Literals.ESTRUCTURAL_FEATURE__DEFAULT_VALUE_LITERAL },
          context);
      if (defaultValue != null)
      {
        getRootEValidator(context).validate(eDataType, defaultValue, diagnostic, context);
      }
      diagnostics.add(diagnostic);
    }
    return result;
  }
  
  private EEnum getEEnum(EDataType eDataType)
  {
    if (eDataType instanceof EEnum)
    {
      return (EEnum)eDataType;
    }

    EDataType baseType = ExtendedMetaData.INSTANCE.getBaseType(eDataType);
    if (baseType != null)
    {
      return getEEnum(baseType);
    }

    return null;
  }

  protected boolean isBuiltinEDataType(EDataType eDataType)
  {
    EPackage ePackage = eDataType.getEPackage();
    if (ePackage == EcorePackage.eINSTANCE || ePackage == XMLTypePackage.eINSTANCE || ePackage == XMLNamespacePackage.eINSTANCE)
    {
      return true;
    }
    
    EDataType baseType = ExtendedMetaData.INSTANCE.getBaseType(eDataType);
    if (baseType != null)
    {
      return isBuiltinEDataType(baseType);
    }

    EDataType itemType = ExtendedMetaData.INSTANCE.getItemType(eDataType);
    if (itemType != null)
    {
      return isBuiltinEDataType(itemType);
    }

    List<EDataType> memberTypes = ExtendedMetaData.INSTANCE.getMemberTypes(eDataType);
    if (!memberTypes.isEmpty())
    {
      for (EDataType memberType : memberTypes)
      {
        if (!isBuiltinEDataType(memberType))
        {
          return false;
        }
      }
      return true;
    }

    return false;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateETypedElement(ETypedElement eTypedElement, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eTypedElement, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidLowerBound(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidUpperBound(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ConsistentBounds(eTypedElement, diagnostics, context);
    if (result || diagnostics != null) result &= validateETypedElement_ValidType(eTypedElement, diagnostics, context);
    return result;
  }

  /**
   * Validates the ValidLowerBound constraint of '<em>ETyped Element</em>'.
   * <!-- begin-user-doc -->
   * The {@link ETypedElement#getLowerBound() lower bound} must be greater or equal to 0
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateETypedElement_ValidLowerBound(ETypedElement eTypedElement, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    int lowerBound = eTypedElement.getLowerBound();
    boolean result = lowerBound >= 0;
    if (diagnostics != null && !result)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           VALID_LOWER_BOUND,
           "_UI_ETypedElementValidLowerBound_diagnostic",
           new Object[] { lowerBound },
           new Object[] { eTypedElement, EcorePackage.Literals.ETYPED_ELEMENT__LOWER_BOUND },
           context));
    }
    return result;
  }

  /**
   * Validates the ValidUpperBound constraint of '<em>ETyped Element</em>'.
   * <!-- begin-user-doc -->
   * The {@link ETypedElement#getUpperBound() upper bound} must be either
   * {@link ETypedElement#UNBOUNDED_MULTIPLICITY},
   * {@link ETypedElement#UNSPECIFIED_MULTIPLICITY},
   * or greater than 0.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateETypedElement_ValidUpperBound(ETypedElement eTypedElement, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    int upperBound = eTypedElement.getUpperBound();
    boolean result =
      upperBound > 0 ||
        upperBound == ETypedElement.UNSPECIFIED_MULTIPLICITY ||
        upperBound == ETypedElement.UNBOUNDED_MULTIPLICITY;
    if (diagnostics != null && !result)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           VALID_UPPER_BOUND,
           "_UI_ETypedElementValidUpperBound_diagnostic",
           new Object[] { upperBound },
           new Object[] { eTypedElement, EcorePackage.Literals.ETYPED_ELEMENT__UPPER_BOUND },
           context));
    }
    return result;
  }

  /**
   * Validates the ConsistentBounds constraint of '<em>ETyped Element</em>'.
   * <!-- begin-user-doc -->
   * The {@link ETypedElement#getLowerBound() lower bound} must be less than or equal to the {@link ETypedElement#getUpperBound() upper bound},
   * unless the upper bound is one of the two special values
   * {@link ETypedElement#UNBOUNDED_MULTIPLICITY} or {@link ETypedElement#UNSPECIFIED_MULTIPLICITY}.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateETypedElement_ConsistentBounds(ETypedElement eTypedElement, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    int lowerBound = eTypedElement.getLowerBound();
    int upperBound = eTypedElement.getUpperBound();
    boolean result = upperBound < 0 || lowerBound <= upperBound;
    if (diagnostics != null && !result)
    {
      diagnostics.add
        (createDiagnostic
          (Diagnostic.ERROR,
           DIAGNOSTIC_SOURCE,
           CONSISTENT_BOUNDS,
           "_UI_ETypedElementConsistentBounds_diagnostic", 
           new Object[] { lowerBound, upperBound },
           new Object[] { eTypedElement,EcorePackage.Literals.ETYPED_ELEMENT__LOWER_BOUND, EcorePackage.Literals.ETYPED_ELEMENT__UPPER_BOUND },
           context));
    }
    return result;
  }

  /**
   * Validates the ValidType constraint of '<em>ETyped Element</em>'.
   * <!-- begin-user-doc -->
   * The {@link ETypedElement#getEGenericType() type} may be <code>null</code> only if this in an {@link EOperation operation}.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateETypedElement_ValidType(ETypedElement eTypedElement, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    EGenericType eGenericType = eTypedElement.getEGenericType();
    if (eGenericType == null && !(eTypedElement instanceof EOperation))
    {
      result = false;
      if (diagnostics != null)
      {
        diagnostics.add
          (createDiagnostic
            (Diagnostic.ERROR,
             DIAGNOSTIC_SOURCE,
             VALID_TYPE,
             "_UI_ETypedElementNoType_diagnostic",
             null,
             new Object[] { eTypedElement, EcorePackage.Literals.ETYPED_ELEMENT__ETYPE },
             context));
      }
    }
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEStringToStringMapEntry(Map.Entry<?, ?> eStringToStringMapEntry, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return validate_EveryDefaultConstraint((EObject)eStringToStringMapEntry, diagnostics, context);
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEGenericType(EGenericType eGenericType, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eGenericType, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validateEGenericType_ConsistentType(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validateEGenericType_ConsistentBounds(eGenericType, diagnostics, context);
    if (result || diagnostics != null) result &= validateEGenericType_ConsistentArguments(eGenericType, diagnostics, context);
    return result;
  }

  /**
   * Validates the ConsistentType constraint of '<em>EGeneric Type</em>'.
   * <!-- begin-user-doc -->
   * A generic type must not reference both a {@link EGenericType#getEClassifier() classifier}
   * and a {@link EGenericType#getETypeParameter() type parameter}.
   * The referenced type parameter must be in scope, i.e.,
   * its {@link EObject#eContainer()} must be an {@link EcoreUtil#isAncestor(EObject, EObject)} of this generic type.
   * A generic type used as a {@link EClass#getEGenericSuperTypes() generic super type}
   * must have a classifier that refers to a {@link EClass class}.
   * A generic type used as a {@link EGenericType#getETypeArguments() type argument} of a generic type used as a generic super type
   * must specify either a classifier or a type parameter, i.e., it can't be a wildcard.
   * A generic type may omit both the classifier and the type argument to act as a wildcard
   * only when used as a type argument of some generic type,
   * with the above exception.
   * If present, the classifier of generic type used as the {@link ETypedElement#getEType() type} of an {@link EAttribute attribute}
   * must be a {@link EDataType data type}.
   * If present, the classifier of generic type used as the type of a {@link EReference reference}
   * must be a class.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEGenericType_ConsistentType(EGenericType eGenericType, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;

    ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
    EClassifier eClassifier = eGenericType.getEClassifier();
    if (eTypeParameter != null)
    {
      if (eClassifier != null)
      {
        // Can't have both a classifier and a type parameter.
        //
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
               (Diagnostic.ERROR,
                DIAGNOSTIC_SOURCE,
                CONSISTENT_TYPE_NO_TYPE_PARAMETER_AND_CLASSIFIER,
                "_UI_EGenericTypeNoTypeParameterAndClassifier_diagnostic",
                null,
                new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ECLASSIFIER, EcorePackage.Literals.EGENERIC_TYPE__ETYPE_PARAMETER },
                context));
        }
      }
      
      // The referencing generic type must be contained to be in scope
      //
      EObject scope = eTypeParameter.eContainer();
      boolean  inScope = EcoreUtil.isAncestor(scope, eGenericType);
      if (inScope)
      {
        // And even if it is contained, it must not be a forward reference.
        // eTypeParameterIndex == index is allowed when the type parameter is 
        // the type argument of the bound, though,
        // i.e., when the type argument is not nested directly as a child of the type parameter.
        //
        List<?> typeParameters = (List<?>)scope.eGet(eTypeParameter.eContainmentFeature());
        EObject usage = eGenericType; 
        for (EObject container = usage.eContainer(); container != scope; container = container.eContainer())
        {
          usage = container;
        }
        int index = typeParameters.indexOf(usage);
        int eTypeParameterIndex = typeParameters.indexOf(eTypeParameter);
        inScope = index == -1 || 
          index > eTypeParameterIndex ||
          eGenericType.eContainingFeature() != EcorePackage.Literals.ETYPE_PARAMETER__EBOUNDS;
      }

      if (!inScope)
      {
        // The type parameter must be in scope and must not be a forward reference.
        //
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
               (Diagnostic.ERROR,
                DIAGNOSTIC_SOURCE,
                CONSISTENT_TYPE_TYPE_PARAMETER_NOT_IN_SCOPE,
                "_UI_EGenericTypeOutOfScopeTypeParameter_diagnostic",
                null,
                new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ETYPE_PARAMETER },
                context));
        }
      }
    }

    EReference eContainmentFeature = eGenericType.eContainmentFeature();
    if (eContainmentFeature == EcorePackage.Literals.ECLASS__EGENERIC_SUPER_TYPES)
    {
      // When used as a generic super type, there must be a classifier that refers to a class.
      //
      if (!(eGenericType.getEClassifier() instanceof EClass))
      {
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               CONSISTENT_TYPE_CLASS_REQUIRED,
               "_UI_EGenericTypeNoClass_diagnostic",
               null,
               new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ECLASSIFIER },
               context));
        }
      }
    }
    else if (eContainmentFeature == EcorePackage.Literals.EGENERIC_TYPE__ETYPE_ARGUMENTS)
    {
      if (eGenericType.eContainer().eContainmentFeature() == EcorePackage.Literals.ECLASS__EGENERIC_SUPER_TYPES)
      {
        // The type arguments of a generic super type must not be a wildcard.
        //
        if (eClassifier == null && eTypeParameter == null)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            diagnostics.add
              (createDiagnostic
                (Diagnostic.ERROR,
                 DIAGNOSTIC_SOURCE,
                 CONSISTENT_TYPE_WILDCARD_NOT_PERMITTED,
                 "_UI_EGenericTypeNoTypeParameterOrClassifier_diagnostic",
                 null,
                 new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ECLASSIFIER, EcorePackage.Literals.EGENERIC_TYPE__ETYPE_PARAMETER },
                 context));
          }
        }
      }
    }
    else if (eContainmentFeature != null)
    {
      // Wildcards are only allowed in type arguments.
      //
      if (eClassifier == null && eTypeParameter == null)
      {
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               CONSISTENT_TYPE_WILDCARD_NOT_PERMITTED,
               "_UI_EGenericTypeNoTypeParameterOrClassifier_diagnostic",
               null,
               new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ECLASSIFIER, EcorePackage.Literals.EGENERIC_TYPE__ETYPE_PARAMETER },
               context));
        }
      }
      else if (eClassifier != null)
      {
        EObject eContainer = eGenericType.eContainer();
        if (eContainer instanceof EStructuralFeature)
        {
          if (eClassifier instanceof EClass)
          {
            if (eContainer instanceof EAttribute)
            {
              // The classifier of an attribute's generic type must be a data type.
              //
              if (diagnostics == null)
              {
                return false;
              }
              else
              {
                result = false;
                diagnostics.add
                  (createDiagnostic
                    (Diagnostic.ERROR,
                     DIAGNOSTIC_SOURCE,
                     CONSISTENT_TYPE_CLASS_NOT_PERMITTED,
                     "_UI_EAttributeNoDataType_diagnostic",
                     null,
                     new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ECLASSIFIER },
                     context));
              }
            }
          }
          else if (eClassifier instanceof EDataType)
          {
            if (eContainer instanceof EReference)
            {
              // The classifier of an references's generic type must be a class.
              //
              if (diagnostics == null)
              {
                return false;
              }
              else
              {
                result = false;
                diagnostics.add
                  (createDiagnostic
                    (Diagnostic.ERROR,
                     DIAGNOSTIC_SOURCE,
                     CONSISTENT_TYPE_DATA_TYPE_NOT_PERMITTED,
                     "_UI_EReferenceNoClass_diagnostic",
                     null,
                     new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ECLASSIFIER },
                     context));
              }
            }
          }
        }
      }
    }
    
    if (eClassifier != null && eContainmentFeature != null && eContainmentFeature != EcorePackage.Literals.ETYPED_ELEMENT__EGENERIC_TYPE)
    {
      // A primitive type can only be used as the generic type of a typed element.
      //
      String instanceClassName = eClassifier.getInstanceClassName();
      if (instanceClassName == "boolean" ||
            instanceClassName == "byte" ||
            instanceClassName == "char" ||
            instanceClassName == "double" ||
            instanceClassName == "float" ||
            instanceClassName == "int" ||
            instanceClassName == "long" ||
            instanceClassName == "short")
      {
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               CONSISTENT_TYPE_PRIMITIVE_TYPE_NOT_PERMITTED,
               "_UI_EGenericTypeInvalidPrimitiveType_diagnostic",
               new Object[] { instanceClassName },
               new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ECLASSIFIER },
               context));
        }
      }
    }
    return result;
  }

  /**
   * Validates the ConsistentBounds constraint of '<em>EGeneric Type</em>'.
   * <!-- begin-user-doc -->
   * A generic type may have bounds only when used as a {@link EGenericType#getETypeArguments() type argument}.
   * A generic type may not have both a {@link EGenericType#getELowerBound() lower} and an {@link EGenericType#getEUpperBound() upper bound}.
   * A generic type may not have bounds
   * as well as a {@link EGenericType#getEClassifier() classifier} or a {@link EGenericType#getETypeParameter() type parameter}.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEGenericType_ConsistentBounds(EGenericType eGenericType, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;

    EGenericType eLowerBound = eGenericType.getELowerBound();
    EGenericType eUpperBound = eGenericType.getEUpperBound();
    if (eLowerBound != null || eUpperBound != null)
    {
      EStructuralFeature eContainmentFeature = eGenericType.eContainmentFeature();
      if (eContainmentFeature == EcorePackage.Literals.EGENERIC_TYPE__ETYPE_ARGUMENTS)
      {
        // Can't have both an upper and lower bound.
        //
        if (eLowerBound != null && eUpperBound != null)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            diagnostics.add
              (createDiagnostic
                (Diagnostic.ERROR,
                 DIAGNOSTIC_SOURCE,
                 CONSISTENT_BOUNDS_NO_LOWER_AND_UPPER,
                 "_UI_EGenericTypeNoUpperAndLowerBound_diagnostic",
                 null,
                 new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ELOWER_BOUND, EcorePackage.Literals.EGENERIC_TYPE__EUPPER_BOUND },
                 context));
          }
        }

        // Can't have a classifier or a type parameter as well as bounds.
        //
        if (eGenericType.getEClassifier() != null || eGenericType.getETypeParameter() != null)
        {
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            diagnostics.add
              (createDiagnostic
                (Diagnostic.ERROR,
                 DIAGNOSTIC_SOURCE,
                 CONSISTENT_BOUNDS_NO_BOUNDS_WITH_TYPE_PARAMETER_OR_CLASSIFIER,
                 "_UI_EGenericTypeNoTypeParameterOrClassifierAndBound_diagnostic",
                 null,
                 new Object[] { eGenericType, eGenericType.getEClassifier() != null ? EcorePackage.Literals.EGENERIC_TYPE__ECLASSIFIER : EcorePackage.Literals.EGENERIC_TYPE__ETYPE_PARAMETER },
                 context));
          }
        }
      }
      else
      {
        // Can only have bounds when used as a type argument.
        //
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               CONSISTENT_BOUNDS_NOT_ALLOWED,
               "_UI_EGenericTypeBoundsOnlyForTypeArgument_diagnostic",
               null,
               new Object[] { eGenericType, eLowerBound != null ? EcorePackage.Literals.EGENERIC_TYPE__ELOWER_BOUND : EcorePackage.Literals.EGENERIC_TYPE__EUPPER_BOUND },
               context));
        }
      }
    }
    return result;
  }

  /**
   * Validates the ConsistentArguments constraint of '<em>EGeneric Type</em>'.
   * <!-- begin-user-doc -->
   * A generic type can have {@link EGenericType#getETypeArguments() type arguments}
   * only if it has a {@link EGenericType#getEClassifier() classifier} that specifies {@link EClassifier#getETypeParameters()};
   * the number of type arguments must match the number of type parameters.
   * It is only a warning for there to be no arguments when there are parameters, but any other mismatch is an error.
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public boolean validateEGenericType_ConsistentArguments(EGenericType eGenericType, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    boolean result = true;
    EClassifier eClassifier = eGenericType.getEClassifier();
    EList<EGenericType> eTypeArguments = eGenericType.getETypeArguments();
    int eTypeArgumentSize = eTypeArguments.size();
    if (eClassifier == null)
    {
      if (eTypeArgumentSize != 0)
      {
        // Can't have type arguments unless there is a classifier
        //
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               CONSISTENT_ARGUMENTS_NONE_ALLOWED,
               "_UI_EGenericTypeNoArguments_diagnostic",
               null,
               new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ETYPE_ARGUMENTS },
               context));
        }
      }
    }
    else
    {
      EList<ETypeParameter> eTypeParameters = eClassifier.getETypeParameters();
      int eTypeParameterSize = eTypeParameters.size();
      if (eTypeArgumentSize == 0)
      {
        if (eTypeParameterSize > 0)
        {
          // Have no arguments when they are allowed is only a warning.
          //
          if (diagnostics == null)
          {
            return false;
          }
          else
          {
            result = false;
            diagnostics.add
              (createDiagnostic
                (Diagnostic.WARNING,
                 DIAGNOSTIC_SOURCE,
                 CONSISTENT_ARGUMENTS_NONE,
                 "_UI_EGenericTypeArgumentsNeeded_diagnostic",
                 new Object [] { eClassifier.getName(), eTypeParameterSize },
                 new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ETYPE_ARGUMENTS },
                 context));

          }
        }
      }
      else if (eTypeArgumentSize != eTypeParameters.size())
      {
        // Incorrect number of type arguments.
        //
        if (diagnostics == null)
        {
          return false;
        }
        else
        {
          result = false;
          diagnostics.add
            (createDiagnostic
              (Diagnostic.ERROR,
               DIAGNOSTIC_SOURCE,
               CONSISTENT_ARGUMENTS_INCORRECT_NUMBER,
               "_UI_EGenericTypeIncorrectArguments_diagnostic", 
               new Object [] { eClassifier.getName(), eTypeArgumentSize, eTypeParameterSize },
               new Object[] { eGenericType, EcorePackage.Literals.EGENERIC_TYPE__ETYPE_ARGUMENTS },
               context));

        }
      }
      else
      {
        Map<ETypeParameter, EGenericType> substitutions = new HashMap<ETypeParameter, EGenericType>();
        for (int i = 0; i < eTypeParameterSize; ++i)
        {
          ETypeParameter eTypeParameter = eTypeParameters.get(i);
          EGenericType eTypeArgument = eTypeArguments.get(i);
          substitutions.put(eTypeParameter, eTypeArgument);
        }
        for (int i = 0; i < eTypeParameterSize; ++i)
        {
          ETypeParameter eTypeParameter = eTypeParameters.get(i);
          EGenericType eTypeArgument = eTypeArguments.get(i);
          if (!isValidSubstitution(eTypeArgument, eTypeParameter, substitutions))
          {
            if (diagnostics == null)
            {
              return false;
            }
            else
            {
              result = false;
              diagnostics.add
                (createDiagnostic
                  (Diagnostic.ERROR,
                   DIAGNOSTIC_SOURCE,
                   CONSISTENT_ARGUMENTS_INVALID_SUBSTITUTION,
                   "_UI_EGenericTypeArgumentInvalidSubstitution_diagnostic", 
                    new Object [] 
                    { 
                      getObjectLabel(eTypeArgument, context), 
                      getObjectLabel(eTypeParameter, context) 
                    },
                   new Object[] { eGenericType, eTypeArgument, eTypeParameter, EcorePackage.Literals.EGENERIC_TYPE__ETYPE_ARGUMENTS },
                   context));
            }
          }
        }
      }
    }
    return result;
  }

  /**
   * Returns whether the generic type argument is a valid substitution for the type parameter.
   * A generic type is a valid substitution 
   * if it is {@link #isBounded(EGenericType, EGenericType, Map) bounded} by 
   * every {@link ETypeParameter#getEBounds() bound} of the type parameter.
   * It follows that for a type parameter without bounds, every type argument is a valid substitution.
   * @param eTypeArgument the generic type argument to consider.
   * @param eTypeParameter the type parameter in question.
   * @return whether the generic type argument is a valid substitution for the type parameter.
   */
  protected boolean isValidSubstitution(EGenericType eTypeArgument, ETypeParameter eTypeParameter, Map<ETypeParameter, EGenericType> substitutions)
  {
    EList<EGenericType> eBounds = eTypeParameter.getEBounds();
    if (!eBounds.isEmpty())
    {
      if (eTypeArgument.getEClassifier() == null && 
            eTypeArgument.getETypeParameter() == null &&
            eTypeArgument.getEUpperBound() == null && 
            eTypeArgument.getELowerBound() == null)
      {
        return true;
      }
      for (EGenericType eBound : eBounds)
      {
        if (!isBounded(eTypeArgument, eBound, substitutions))
        {
          return false;
        }
      }
    }
    return true;
  }
  
  /**
   * Returns whether the first generic type is bounded by the second.
   * If they both reference a classifier, 
   * then the classifier of the first must be bounded by the classifier of the second,
   * and the type arguments must {@link #matchingTypeArguments(EList, EList, Map) match}.
   * A classifier is bounded by another classifier,
   * if they are the same classifier,
   * if both are classes and the first is a {@link EClass#isSuperTypeOf(EClass)} the second,
   * or if both have an non-null {@link EClassifier#getInstanceClass() instance class} 
   * for which the first is {@link Class#isAssignableFrom(Class) assignable from} the second,
   * or, failing all these, if they have non-null {@link EClassifier#getInstanceTypeName()} that are equal.
   * If the bound references a classifier, and the generic type argument references a type parameter,
   * one of the {@link ETypeParameter#getEBounds() bounds} of that type parameter must be bounded by bound.
   * If the bound has a {@link EGenericType#getELowerBound() lower bound}, 
   * the generic type argument must be bounded by that lower bound.
   * If the bound has an {@link EGenericType#getEUpperBound() upper bound}, 
   * the generic type argument must be bounded by that upper bound.
   * If the bound references a type parameter,
   * the generic type argument must be bounded by every bound of that type parameter.
   * If the bound has a lower bound, 
   * the generic type argument must be bounded by it.
   * If the bound has an upper bound, 
   * the generic type argument must be bound that upper bound.
   * Failing all these cases, the bound is a wildcard with no constraint, and the type argument is bounded.
   * @param eGenericType the generic type in question.
   * @param eBound the bound it's being assessed against.
   * @param substitutions the map of substitutions that are in effect.
   * @return whether the first generic type is bounded by the second.
   */
  public static boolean isBounded(EGenericType eGenericType, EGenericType eBound, Map<? extends ETypeParameter, ? extends EGenericType> substitutions)
  {
    if (eGenericType == eBound)
    {
      return true;
    }

    // Check if the bound specifies a classifier...
    //
    EClassifier eBoundEClassifier = eBound.getEClassifier();
    if (eBoundEClassifier != null)
    {
      // If the type also specifies a classifier...
      //
      EClassifier eClassifier = eGenericType.getEClassifier();
      if (eClassifier != null)
      {
        // If the are the same then it is bounded properly...
        //
        if (eBoundEClassifier != eClassifier)
        {
          // We test their relationship either via them both being classes...
          //
          if (eBoundEClassifier instanceof EClass && eClassifier instanceof EClass)
          {
            EClass eClass = (EClass)eClassifier;

            // Since we will do the processing recursively, we need to ensure we don't stack overflow if there is a circular super type.
            //
            if (INSTANCE.validateEClass_NoCircularSuperTypes(eClass, null, null))
            {
              // Determine if there is a bounding generic super type.
              //
              for (EGenericType eGenericSuperType : eClass.getEGenericSuperTypes())
              {
                // Set up the substitutions of any type parameters this class has with respect to the type arguments for them.
                //
                Map<? extends ETypeParameter, ? extends EGenericType> localSubstitutions = substitutions;
  
                // Test if there are type parameters that might require substitution.
                //
                EList<ETypeParameter> eTypeParameters = eClass.getETypeParameters();
                int size = eTypeParameters.size();
                if (size > 0)
                {
                  EList<EGenericType> eTypeArguments = eGenericType.getETypeArguments();
                  if (size == eTypeArguments.size())
                  {
                    HashMap<ETypeParameter, EGenericType> additionalLocalSubstitutions = new HashMap<ETypeParameter, EGenericType>(substitutions);
                    for (int i = 0; i < size; ++i)
                    {
                      additionalLocalSubstitutions.put(eTypeParameters.get(i), eTypeArguments.get(i));
                    }
                    localSubstitutions = additionalLocalSubstitutions;
                  }
                }
                if (isBounded(eGenericSuperType, eBound, localSubstitutions))
                {
                  return true;
                }
              }
            }
            
            // If none of the generic super types are bounded, then we've failed.
            //
            return false;
          }
          else
          {
            // Or we test their relationship via their instance classes, if they have them.
            //
            Class<?> eBoundClass = eBoundEClassifier.getInstanceClass();
            if (eBoundClass != null)
            {
              Class<?> eClassifierClass = eClassifier.getInstanceClass();
              if (eClassifierClass != null && !eBoundClass.isAssignableFrom(eClassifierClass))
              {
                return false;
              }
              // If the classifier being bounded doesn't have type parameters...
              //
              else if (eClassifier.getETypeParameters().isEmpty())
              {
                // Then there won't be any type arguments,
                // so even if the bound has type arguments, 
                // we must assume the classifier is bounded
                // because we don't know that the implementation class in Java isn't properly bounded.
                // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=331475
                //
                return true;
              }
            }
          }
        }

        // If neither approach finds a contradiction, we must assume they are okay and then check all the arguments.
        //
        return matchingTypeArguments(eGenericType.getETypeArguments(), eBound.getETypeArguments(), substitutions);
      }
      else
      {
        ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
        if (eTypeParameter != null)
        {
          EGenericType substitution = substitutions.get(eTypeParameter);
          if (substitution == eGenericType)
          {
            return true;
          }
          else if (substitution != null && substitution.getEUpperBound() != eGenericType && substitution.getELowerBound() != eGenericType && !isCircularSubstitution(eTypeParameter, substitution, substitutions))
          {
            return isBounded(substitution, eBound, substitutions);
          }
          else
          {
            // If there is a type parameter, one of its bounds must be bounded by the bound.
            //
            boolean result = false;
            for (EGenericType eTypeParameterBound : eTypeParameter.getEBounds())
            {
              if (isBounded(eTypeParameterBound, eBound, substitutions))
              {
                result = true;
                break;
              }
            }
            return result;
          }
        }
        else
        {
          // If there is a upper bound, the bound must bound it.
          //
          EGenericType eUpperBound = eGenericType.getEUpperBound();
          if (eUpperBound != null)
          {
            return isBounded(eUpperBound, eBound, substitutions);
          }
          else
          {
            // Failing all those cases, there must be an lower bound that bounds it.
            //
            EGenericType eLowerBound = eGenericType.getELowerBound();
            return eLowerBound != null && isBounded(eLowerBound, eBound, substitutions);
          }
        }
      }
    }
    else
    {
      ETypeParameter eBoundETypeParameter = eBound.getETypeParameter();
      if (eBoundETypeParameter != null)
      {
        ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
        if (eTypeParameter == eBoundETypeParameter)
        {
          return true;
        }
        else 
        {
          EGenericType substitution = substitutions.get(eBoundETypeParameter);
          if (substitution != null)
          {
            return isBounded(eGenericType, substitution, substitutions);
          }
          else if (eTypeParameter != null)
          {
            substitution = substitutions.get(eTypeParameter);
            if (substitution == eGenericType)
            {
              return true;
            }
            else if (substitution != null && substitution.getEUpperBound() != eGenericType && substitution.getELowerBound() != eGenericType)
            {
              return isBounded(substitution, eBound, substitutions);
            }
            else
            {
              boolean result = false;
              for (EGenericType eTypeParameterEBound : eTypeParameter.getEBounds())
              {
                if (!(result = isBounded(eTypeParameterEBound, eBound, substitutions)))
                {
                  for (EGenericType eBoundETypeParameterEBound : eBoundETypeParameter.getEBounds())
                  {
                    if (isBounded(eTypeParameterEBound, eBoundETypeParameterEBound, substitutions))
                    {
                      result = true;
                      break;
                    }
                  }
                }
                if (!result)
                {
                  return false;
                }
              }
              return result;
            }
          }
          else
          {
            if (eGenericType.getEUpperBound() != null)
            {
              return isBounded(eGenericType.getEUpperBound(), eBound, substitutions);
            }
            else
            {
              return false;
            }
          }
        }
      }
      else
      {
        // If the generic type is a wildcard, it can't be bounded by another wildcard.
        //
        if (eGenericType.getETypeParameter() == null && eGenericType.getEClassifier() == null)
        {
          return false;
        }
        EGenericType eBoundEUpperBound = eBound.getEUpperBound();
        if (eBoundEUpperBound != null)
        {
          return isBounded(eGenericType, eBoundEUpperBound, substitutions);
        }
        else
        {
          EGenericType eBoundELowerBound = eBound.getELowerBound();
          if (eBoundELowerBound != null)
          {
            // If there is an lower bound, the type argument must bound it.
            //
            return isBounded(eBoundELowerBound, eGenericType, substitutions);
          }
          
          // The bound is a wildcard with no constraints.
          //
          return false;
        }
      }
    }
  }

  private static boolean isCircularSubstitution(ETypeParameter eTypeParameter, EGenericType substitution, Map<? extends ETypeParameter, ? extends EGenericType> substitutions)
  {
    Set<ETypeParameter> visited = new HashSet<ETypeParameter>();
    for (ETypeParameter otherETypeParameter = substitution.getETypeParameter(); otherETypeParameter != null; )
    {
      if (otherETypeParameter == eTypeParameter)
      {
        return true;
      }

      if (!visited.add(otherETypeParameter))
      {
        return false;
      }

      EGenericType otherSubstitution = substitutions.get(otherETypeParameter);
      if (otherSubstitution == null)
      {
        return false;
      }

      otherETypeParameter = otherSubstitution.getETypeParameter();
    }

    return false;
  }

  public static boolean matchingTypeArguments
    (EList<EGenericType> eTypeArguments1, EList<EGenericType> eTypeArguments2, Map<? extends ETypeParameter, ? extends EGenericType> substitutions)
  {
    int size = eTypeArguments1.size();
    if (size != eTypeArguments2.size())
    {
      return false;
    }
    else
    {
      for (int i = 0; i < size; ++i)
      {
        EGenericType eTypeArgument1 = eTypeArguments1.get(i);
        EGenericType eTypeArgument2 = eTypeArguments2.get(i);
        if (!isMatching(eTypeArgument1, eTypeArgument2, substitutions))
        {
          return false;
        }
      }
      return true;
    }
  }

  public static boolean isMatching(EGenericType eGenericType, EGenericType eBound, Map<? extends ETypeParameter, ? extends EGenericType> substitutions)
  {
    if (eGenericType == eBound)
    {
      return true;
    }

    // Check if the bound specifies a classifier...
    //
    EClassifier eBoundEClassifier = eBound.getEClassifier();
    if (eBoundEClassifier != null)
    {
      // If the type also specifies a classifier...
      //
      EClassifier eClassifier = eGenericType.getEClassifier();
      if (eClassifier != null)
      {
        // If they are the same classifier, they are of course equal.
        //
        if (eClassifier != eBoundEClassifier)
        {
          // Consider the instance type names they wrap 
          // to see if they are non-null and equal.
          //
          String instanceTypeName1 = eClassifier.getInstanceTypeName(); 
          String instanceTypeName2 = eBoundEClassifier.getInstanceTypeName(); 
  
          // I.e., the classifiers are considered equal if they wrap the same non-null type.
          //
          if (instanceTypeName1 == null || !instanceTypeName1.equals(instanceTypeName2))
          {
            return false;
          }
        }
          
        // TODO What about the instance type name and the fact that we should be matching its type argument structure?
        // If they match so far, we must assume they are okay and then check all the arguments.
        //
        return equalTypeArguments(eGenericType.getETypeArguments(), eBound.getETypeArguments(), substitutions);
      }
      else
      {
        return false;
      }
    }
    else
    {
      ETypeParameter eBoundETypeParameter = eBound.getETypeParameter();
      if (eBoundETypeParameter != null)
      {
        ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
        if (eTypeParameter == eBoundETypeParameter)
        {
          return true;
        }
        else
        {
          EGenericType substitution = substitutions.get(eTypeParameter);
          if (substitution != null)
          {
            return substitution == eGenericType || isMatching(substitution, eBound, substitutions);
          }
          else if ((substitution = substitutions.get(eBoundETypeParameter)) != null)
          {
            return substitution == eBound || isMatching(eGenericType, substitution, substitutions);
          }
          else
          {
            return false;
          }
        }
      }
      else
      {
        // If the generic type is a different wildcard, it doesn't match.
        //
        if (eGenericType.getEClassifier() == null && eGenericType.getETypeParameter() == null)
        {
          return
            isMatching(eGenericType.getELowerBound(), eBound.getELowerBound(), substitutions) &&
              isMatching(eGenericType.getEUpperBound(), eBound.getEUpperBound(), substitutions);
        }
        else
        {
          EGenericType eBoundEUpperBound = eBound.getEUpperBound();
          if (eBoundEUpperBound != null)
          {
            return isBounded(eGenericType, eBoundEUpperBound, substitutions);
          }
          else
          {
            EGenericType eBoundELowerBound = eBound.getELowerBound();
            if (eBoundELowerBound != null)
            {
              // Reverse the test.
              //
              return isMatching(eBoundELowerBound, eGenericType, substitutions);
            }
            
            // The bound is a wildcard with no constraints.
            //
            return  true;
          }
        }
      }
    }
  }

  public static boolean equalTypeArguments
    (EList<EGenericType> eTypeArguments1, EList<EGenericType> eTypeArguments2, Map<? extends ETypeParameter, ? extends EGenericType> substitutions)
  {
    int size = eTypeArguments1.size();
    if (size != eTypeArguments2.size())
    {
      return false;
    }
    else
    {
      for (int i = 0; i < size; ++i)
      {
        EGenericType eTypeArgument1 = eTypeArguments1.get(i);
        EGenericType eTypeArgument2 = eTypeArguments2.get(i);
        if (!equalTypeArguments(eTypeArgument1, eTypeArgument2, substitutions))
        {
          return false;
        }
      }
      return true;
    }
  }

  public static boolean equalTypeArguments
    (EGenericType eGenericType1, EGenericType eGenericType2, Map<? extends ETypeParameter, ? extends EGenericType> substitutions)
  {
    // If they are the same instance they are equal.
    //
    if (eGenericType1 == eGenericType2)
    {
      return true;
    }
    // If one is null (but the other is not) then they are not equal.
    //
    else if (eGenericType1 == null || eGenericType2 == null)
    {
      return false;
    }
    else
    {
      // Consider the classifiers in a special way 
      // to take into account the fact they they often acts as wrappers for instance type names
      // and that two classifiers that wrap the same instance type name should be considered equal.
      //
      EClassifier eClassifier1 = eGenericType1.getEClassifier();
      EClassifier eClassifier2 = eGenericType2.getEClassifier();
      
      // If they are the same classifier, they are of course equal.
      //
      if (eClassifier1 != eClassifier2)
      {
        // If they both aren't null...
        //
        if (eClassifier1 != null && eClassifier2 != null)
        {
          // Consider the instance type names they wrap 
          // to see if they are non-null and equal.
          //
          String instanceTypeName1 = eClassifier1.getInstanceTypeName(); 
          String instanceTypeName2 = eClassifier2.getInstanceTypeName(); 

          // I.e., the classifiers are considered equal if they wrap the same non-null type.
          //
          if (instanceTypeName1 == null || !instanceTypeName1.equals(instanceTypeName2))
          {
            return false;
          }
        }
        // If one is null (but the other is not) then they can't be equal.
        //
        else if (eClassifier1 != null || eClassifier2 != null)
        {
          return false;
        }
      }
      
      ETypeParameter eTypeParameter1 = eGenericType1.getETypeParameter();
      EGenericType substitution = substitutions.get(eTypeParameter1);
      if (substitution != null)
      {
        return equalTypeArguments(substitution, eGenericType2, substitutions);
      }
      ETypeParameter eTypeParameter2 = eGenericType2.getETypeParameter();
      substitution = substitutions.get(eTypeParameter2);
      if (substitution != null)
      {
        return equalTypeArguments(eGenericType1, substitution, substitutions);
      }

      // The arguments, type parameters, lower bounds and upper bounds must be equal type arguments.
      //
      return
        eTypeParameter1 == eTypeParameter2 &&
          equalTypeArguments(eGenericType1.getETypeArguments(), eGenericType2.getETypeArguments(), substitutions) &&
          equalTypeArguments(eGenericType1.getELowerBound(), eGenericType2.getELowerBound(), substitutions) &&
          equalTypeArguments(eGenericType1.getEUpperBound(), eGenericType2.getEUpperBound(), substitutions);
    }
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateETypeParameter(ETypeParameter eTypeParameter, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    if (!validate_NoCircularContainment(eTypeParameter, diagnostics, context)) return false;
    boolean result = validate_EveryMultiplicityConforms(eTypeParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryDataValueConforms(eTypeParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryReferenceIsContained(eTypeParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryBidirectionalReferenceIsPaired(eTypeParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryProxyResolves(eTypeParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_UniqueID(eTypeParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryKeyUnique(eTypeParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validate_EveryMapEntryUnique(eTypeParameter, diagnostics, context);
    if (result || diagnostics != null) result &= validateENamedElement_WellFormedName(eTypeParameter, diagnostics, context);
    return result;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEBigDecimal(BigDecimal eBigDecimal, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEBigInteger(BigInteger eBigInteger, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEBoolean(boolean eBoolean, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEBooleanObject(Boolean eBooleanObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEByte(byte eByte, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEByteArray(byte[] eByteArray, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEByteObject(Byte eByteObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEChar(char eChar, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateECharacterObject(Character eCharacterObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEDate(Date eDate, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEDiagnosticChain(DiagnosticChain eDiagnosticChain, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEDouble(double eDouble, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEDoubleObject(Double eDoubleObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEEList(EList<?> eeList, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEEnumerator(Enumerator eEnumerator, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEFeatureMap(FeatureMap eFeatureMap, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEFeatureMapEntry(FeatureMap.Entry eFeatureMapEntry, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEFloat(float eFloat, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEFloatObject(Float eFloatObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEInt(int eInt, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEIntegerObject(Integer eIntegerObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEJavaClass(Class<?> eJavaClass, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEJavaObject(Object eJavaObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateELong(long eLong, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateELongObject(Long eLongObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEMap(Map<?, ?> eMap, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEResource(Resource eResource, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEResourceSet(ResourceSet eResourceSet, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEShort(short eShort, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEShortObject(Short eShortObject, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEString(String eString, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateETreeIterator(TreeIterator<?> eTreeIterator, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  public boolean validateEInvocationTargetException(InvocationTargetException eInvocationTargetException, DiagnosticChain diagnostics, Map<Object, Object> context)
  {
    return true;
  }

  /**
   * Returns the resource locator that will be used to fetch messages for this validator's diagnostics.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated
   */
  @Override
  public ResourceLocator getResourceLocator()
  {
    // TODO
    // Specialize this to return a resource locator for messages specific to this validator.
    // Ensure that you remove @generated or mark it @generated NOT
    return super.getResourceLocator();
  }

  /**
   * A utility for parsing generic types and generic type parameters.
   * @since 2.3
   */
  public static class EGenericTypeBuilder
  {
    /**
     * A singleton instance of the generic type build.
     */
    public static final EGenericTypeBuilder INSTANCE = new EGenericTypeBuilder();

    private static final char [] NO_CHARS = {};

    /**
     * Parses an instance type name and returns a diagnostic representing the result of the analysis.
     * The {@link Diagnostic#getData() data} of the diagnostic will contain as the first object, the resulting {@link EGenericType generic type}.
     * @param instanceTypeName an instance type name.
     * @return the diagnostic result of the analysis.
     */
    public Diagnostic parseInstanceTypeName(final String instanceTypeName)
    {
      BasicDiagnostic placeholder = new BasicDiagnostic();
      char [] instanceTypeNameCharacterArray = instanceTypeName == null ? NO_CHARS: instanceTypeName.toCharArray();
      EGenericType eGenericType = handleInstanceTypeName(instanceTypeNameCharacterArray, 0, instanceTypeNameCharacterArray.length, placeholder);
      BasicDiagnostic result =
        createDiagnostic
          (placeholder.getSeverity(),
           DIAGNOSTIC_SOURCE, 
           WELL_FORMED_INSTANCE_TYPE_NAME,
           "_UI_EClassifierInstanceTypeNameAnalysisResult_diagnostic", 
           new Object [] { instanceTypeName },
           new Object [] { eGenericType, instanceTypeName });
      result.addAll(placeholder);
      return result;
    }

    /**
     * Parses an instance type name and returns its representation as an {@link EGenericType generic type}.
     * @param instanceTypeName an instance type name.
     * @return the generic type representation.
     * @since 2.15
     */
    public EGenericType buildEGenericType(String instanceTypeName)
    {
      char [] instanceTypeNameCharacterArray = instanceTypeName == null ? NO_CHARS: instanceTypeName.toCharArray();
      EGenericType eGenericType = handleInstanceTypeName(instanceTypeNameCharacterArray, 0, instanceTypeNameCharacterArray.length, null);
      return eGenericType;
    }

    /**
     * Parses a list of type parameters and returns a diagnostic representing the result of the analysis.
     * The {@link Diagnostic#getData() data} of the diagnostic will contain as the first object, the resulting list of {@link ETypeParameter type parameters}.
     * @param typeParameterList a comma separated list of type parameters delimited by '&lt;' and '>'.
     * @return the diagnostic result of the analysis.
     */
    public Diagnostic parseTypeParameterList(final String typeParameterList)
    {
      BasicDiagnostic placeholder = new BasicDiagnostic();
      char [] instanceTypeNameCharacterArray = typeParameterList == null ? NO_CHARS : typeParameterList.toCharArray();
      List<ETypeParameter> eTypeParameters = handleTypeParameters(instanceTypeNameCharacterArray, 0, instanceTypeNameCharacterArray.length, placeholder);
      BasicDiagnostic result =
        createDiagnostic
          (placeholder.getSeverity(),
           DIAGNOSTIC_SOURCE,
           WELL_FORMED_INSTANCE_TYPE_NAME,
           "_UI_EClassifierInstanceTypeNameAnalysisResult_diagnostic",
           new Object [] { typeParameterList },
           new Object [] { eTypeParameters, typeParameterList });
      result.addAll(placeholder);
      return result;
    }

    /**
     * Parses a list of type parameters and returns its representation as a list of {@link ETypeParameter type parameters}.
     * @param typeParameterList a comma separated list of type parameters delimited by '&lt;' and '>'.
     * @return the typed parameter list representation.
     * @since 2.15
     */
    public List<ETypeParameter> buildETypeParameters(String typeParameterList)
    {
      char [] instanceTypeNameCharacterArray = typeParameterList == null ? NO_CHARS : typeParameterList.toCharArray();
      List<ETypeParameter> eTypeParameters = handleTypeParameters(instanceTypeNameCharacterArray, 0, instanceTypeNameCharacterArray.length, null);
      return eTypeParameters;
    }

    /**
     * Parses a list of type arguments and returns a diagnostic representing the result of the analysis.
     * The {@link Diagnostic#getData() data} of the diagnostic will contain as the first object, the resulting list of {@link EGenericType type arguments}.
     * @param typeArgumentList a comma separated list of type arguments.
     * @return the diagnostic result of the analysis.
     * @since 2.4
     */
    public Diagnostic parseTypeArgumentList(final String typeArgumentList)
    {
      BasicDiagnostic placeholder = new BasicDiagnostic();
      char [] instanceTypeNameCharacterArray = typeArgumentList == null ? NO_CHARS : typeArgumentList.toCharArray();
      List<EGenericType> eTypeArguments = handleTypeArguments(instanceTypeNameCharacterArray, 0, instanceTypeNameCharacterArray.length, placeholder);
      BasicDiagnostic result =
        createDiagnostic
          (placeholder.getSeverity(),
           DIAGNOSTIC_SOURCE,
           WELL_FORMED_INSTANCE_TYPE_NAME,
           "_UI_EClassifierInstanceTypeNameAnalysisResult_diagnostic",
           new Object [] { typeArgumentList },
           new Object [] { eTypeArguments, typeArgumentList });
      result.addAll(placeholder);
      return result;
    }

    /**
     * Parses a list of type arguments and returns its representation as a list of {@link EGenericType type arguments}.
     * @param typeArgumentList a comma separated list of type arguments.
     * @return the generic type list representation.
     * @since 2.15
     */
    public List<EGenericType> buildEGenericTypes(String typeArgumentList)
    {
      char [] instanceTypeNameCharacterArray = typeArgumentList == null ? NO_CHARS : typeArgumentList.toCharArray();
      List<EGenericType> eTypeArguments = handleTypeArguments(instanceTypeNameCharacterArray, 0, instanceTypeNameCharacterArray.length, null);
      return eTypeArguments;
    }

    /**
     * Parses a type parameter and returns a diagnostic representing the result of the analysis.
     * The {@link Diagnostic#getData() data} of the diagnostic will contain as the first object, the resulting {@link ETypeParameter type parameter}.
     * @param typeParameter a type parameter.
     * @return the diagnostic result of the analysis.
     */
    public Diagnostic parseTypeParameter(final String typeParameter)
    {
      BasicDiagnostic placeholder = new BasicDiagnostic();
      char [] instanceTypeNameCharacterArray = typeParameter == null ? NO_CHARS : typeParameter.toCharArray();
      ETypeParameter eTypeParameter = handleTypeParameter(instanceTypeNameCharacterArray, 0, instanceTypeNameCharacterArray.length, placeholder);
      BasicDiagnostic result =
        createDiagnostic
          (placeholder.getSeverity(),
           DIAGNOSTIC_SOURCE,
           WELL_FORMED_INSTANCE_TYPE_NAME,
           "_UI_EClassifierInstanceTypeNameAnalysisResult_diagnostic",
           new Object [] { typeParameter },
           new Object [] { eTypeParameter, typeParameter });
      result.addAll(placeholder);
      return result;
    }

    /**
     * Parses a type parameter and returns its representation as {@link ETypeParameter type parameter}.
     * @param typeParameter a type parameter.
     * @return the diagnostic result of the analysis.
     * @since 2.15
     */
    public ETypeParameter buildETypeParameter(String typeParameter)
    {
      char [] instanceTypeNameCharacterArray = typeParameter == null ? NO_CHARS : typeParameter.toCharArray();
      ETypeParameter eTypeParameter = handleTypeParameter(instanceTypeNameCharacterArray, 0, instanceTypeNameCharacterArray.length, null);
      return eTypeParameter;
    }

    /**
     * Finds or creates an {@link EClassifier classifier} with the given instance type name.
     * @param instanceTypeName the instance type name for which a classifier is needed.
     * @return a classifier with the instance type name.
     */
    protected EClassifier resolveEClassifier(String instanceTypeName)
    {
      EDataType eDataType = EcoreFactory.eINSTANCE.createEDataType();
      eDataType.setInstanceTypeName(instanceTypeName);
      return eDataType;
    }

    /**
     * Creates a new diagnostic for a problem at the given index.
     * @param diagnostics the target for the new diagnostic.
     * @param key the key for the message.
     * @param substitutions the substitutions for the key; <code>null</code> if there are no substitutions.
     * @param index the index at which the problem occurred.
     */
    protected void report(DiagnosticChain diagnostics, String key, Object [] substitutions, int index)
    {
      report(diagnostics, getString(key, substitutions), index);
    }

    /**
     * Creates a new diagnostic for a problem at the given index.
     * @param diagnostics the target for the new diagnostic.
     * @param message the text describing the problem.
     * @param index the index at which the problem occurred.
     */
    protected void report(DiagnosticChain diagnostics, String message, int index)
    {
      if (diagnostics != null)
      {
        diagnostics.add
          (new BasicDiagnostic
             (Diagnostic.ERROR,
              DIAGNOSTIC_SOURCE,
              WELL_FORMED_INSTANCE_TYPE_NAME,
              message, 
              new Object [] { index }));
      }
    }

    /**
     * A well formed instance type name must syntactically denote a valid Java type name;
     * names denoting keywords are considered well formed.
     * It must start with a qualified name consisting of one or more "." separated identifiers,
     * where each identifier must start with a {@link Character#isJavaIdentifierStart(int) Java identifier start character},
     * that is followed by zero or more {@link Character#isJavaIdentifierPart(int) Java identifier part characters}.
     * The methods {@link #isIdentifierStart(int)} and {@link #isIdentifierPart(int)} are used so that this behavior can be specialized.
     * This qualified name may optionally be followed by zero or more pairs of "[]" characters
     * or by type arguments consisting of the pair of "&lt;>" characters
     * with embedded {@link #handleTypeArguments(char[], int, int, DiagnosticChain) well formed type arguments}.
     * @param instanceTypeName the instance type name in question.
     * @param start the start of the characters under consideration.
     * @param end the end of the characters under consideration.
     * @param diagnostics the target in which to accumulate diagnostics.
     * @return the generic type representing the instance type name.
     */
    protected EGenericType handleInstanceTypeName(char [] instanceTypeName, int start, int end, DiagnosticChain diagnostics)
    {
      EGenericType eGenericType = EcoreFactory.eINSTANCE.createEGenericType();
      StringBuilder qualifiedName = new StringBuilder();
      int identifierStart = -1;
      int identifierLast = -1;
      int brackets = 0;
      List<EGenericType> typeArguments = null;
      LOOP:
      for (int i = start; i < end; i = Character.offsetByCodePoints(instanceTypeName, 0, instanceTypeName.length, i, 1))
      {
        int codePoint = Character.codePointAt(instanceTypeName, i);
        if (codePoint == '[')
        {
          if (identifierStart == -1 && (qualifiedName.length() == 0 || qualifiedName.charAt(qualifiedName.length() - 1) == '.'))
          {
            report
              (diagnostics, 
               "_UI_EClassifierInstanceTypeNameBracketWithoutPrecedingIdentifier_diagnostic", 
               new Object [] { i }, 
               i);
            return eGenericType;
          }
          else 
          {
            for (int j = i + 1; j < end; j = Character.offsetByCodePoints(instanceTypeName, 0, instanceTypeName.length, j, 1))
            {
              codePoint = Character.codePointAt(instanceTypeName, j);
              if (codePoint == ']')
              {
                i = j;
                ++brackets;
                continue LOOP;
              }
              else if (!Character.isWhitespace(codePoint))
              {
                report
                  (diagnostics, 
                   "_UI_EClassifierInstanceTypeNameNoClosingBracket2_diagnostic", 
                   new Object [] { j, new String(Character.toChars(codePoint))}, 
                   j);
                return eGenericType;
              }
            }
            report
              (diagnostics, 
               "_UI_EClassifierInstanceTypeNameNoClosingBracket_diagnostic", 
               new Object [] { end }, 
               end);
            return eGenericType;
          }
        }
        else if (brackets > 0)
        {
          if (!Character.isWhitespace(codePoint))
          {
            report
              (diagnostics, 
               "_UI_EClassifierInstanceTypeNameBracketExpected_diagnostic", 
               new Object [] { i, new String(Character.toChars(codePoint))}, 
               i);
            return eGenericType;
          }
        }
        else if (codePoint == '.')
        {
          if (identifierStart == -1)
          {
            if (qualifiedName.length() == 0 || qualifiedName.charAt(qualifiedName.length() - 1) == '.')
            {
              report
                (diagnostics, 
                 "_UI_EClassifierInstanceTypeNameDotWithoutPrecedingIdentifier_diagnostic", 
                 new Object [] { i }, 
                 i);
              return eGenericType;
            }
            else
            {
              qualifiedName.append('.');
            }
          }
          else
          {
            qualifiedName.append(instanceTypeName, identifierStart, identifierLast - identifierStart + 1);
            qualifiedName.append('.');
            identifierStart = -1;
            identifierLast = -1;
          }
        }
        else if (identifierStart != -1 ? isIdentifierPart(codePoint) : isIdentifierStart(codePoint))
        {
          if (identifierStart == -1)
          {
            if (qualifiedName.length() > 0 && qualifiedName.charAt(qualifiedName.length() - 1) != '.')
            {
              report
                (diagnostics, 
                 "_UI_EClassifierInstanceTypeNameDotExpectedBeforeIdentifier_diagnostic", 
                 new Object [] { i }, 
                 i);
              return eGenericType;
            }
            identifierStart = i;
          }
          identifierLast = i;
        }
        else if (Character.isWhitespace(codePoint))
        {
          if (identifierStart == -1)
          {
            // Ignore leading whitespace
          }
          else if (qualifiedName.length() == 0 || qualifiedName.charAt(qualifiedName.length() - 1) == '.')
          {
            qualifiedName.append(instanceTypeName, identifierStart, identifierLast - identifierStart + 1);
            identifierStart = -1;
            identifierLast = -1;
          }
          else
          {
            // Ignore trailing whitespace
          }
        }
        else if (codePoint == '<')
        {
          if (identifierStart == -1 && (qualifiedName.length() == 0 || qualifiedName.charAt(qualifiedName.length() - 1) == '.'))
          {
            report
              (diagnostics, 
               "_UI_EClassifierInstanceTypeNameAngleBracketWithoutPrecedingIdentifier_diagnostic", 
               new Object [] { i }, 
               i);
            return eGenericType;
          }
          for (int j = end - 1; j > i; --j)
          {
            if (instanceTypeName[j] == '>')
            {
              typeArguments = handleTypeArguments(instanceTypeName, i + 1, j, diagnostics);
              i = j;
              continue LOOP;
            }
          }
          report
            (diagnostics, 
             "_UI_EClassifierInstanceTypeNameUnterminatedAngleBracket_diagnostic", 
             new Object [] { i }, 
             i);
          return eGenericType;
        }
        else
        {
          report
            (diagnostics, 
             "_UI_EClassifierInstanceTypeNameUnexpectedCharacter_diagnostic", 
             new Object [] { i, new String(Character.toChars(codePoint)) }, 
             i);
          return eGenericType;
        }
      }
      
      if (identifierStart == -1 && (qualifiedName.length() == 0 || qualifiedName.charAt(qualifiedName.length() - 1) == '.'))
      {
        report
          (diagnostics, 
           "_UI_EClassifierInstanceTypeNameExpectingIdentifier_diagnostic", 
           new Object [] { end }, 
           end);
      }
      else
      {
        if (identifierStart != -1)
        {
          qualifiedName.append(instanceTypeName, identifierStart, identifierLast - identifierStart + 1);
        }
        while (brackets-- > 0)
        {
          qualifiedName.append("[]");
        }
        String qualifiedNameString = qualifiedName.toString();
        eGenericType.setEClassifier(resolveEClassifier(qualifiedNameString));
        if (typeArguments != null)
        {
          eGenericType.getETypeArguments().addAll(typeArguments);
        }
      }
      return eGenericType;
    }
    
    /**
     * Returns whether this code point is a valid start of an identifier.
     * @param codePoint the code point in question.
     * @return whether this code point is a valid start of an identifier.
     */
    protected boolean isIdentifierStart(int codePoint)
    {
      return Character.isJavaIdentifierStart(codePoint);
    }

    /**
     * Returns whether this code point is a valid part of an identifier, i.e., whether it's valid after the first character.
     * @param codePoint the code point in question.
     * @return whether this code point is a valid part of an identifier.
     */
    protected boolean isIdentifierPart(int codePoint)
    {
      return Character.isJavaIdentifierPart(codePoint);
    }
    
    /**
     * Well formed type arguments must syntactically denote a comma separated sequence of
     * {@link #handleTypeArgument(char[], int, int, DiagnosticChain) well formed type arguments}.
     * Whitespace before or after arguments is ignored.
     * @param instanceTypeName the instance type name in question.
     * @param start the start of the characters under consideration.
     * @param end the end of the characters under consideration.
     * @param diagnostics the target in which to accumulate diagnostics.
     * @return a list of generic type representing the type arguments.
     */
    protected List<EGenericType> handleTypeArguments(char [] instanceTypeName, int start, int end, DiagnosticChain diagnostics)
    {
      List<EGenericType> result = new ArrayList<EGenericType>();
      int depth = 0;
      int typeArgumentStart = start;
      for (int i = start; i < end; i = Character.offsetByCodePoints(instanceTypeName, 0, instanceTypeName.length, i, 1))
      {
        int codePoint = Character.codePointAt(instanceTypeName, i);
        switch (codePoint)
        {
          case '<':
          {
            ++depth;
            break;
          }
          case '>':
          {
            --depth;
            break;
          }
          case ',':
          {
            if (depth == 0)
            {
              result.add(handleTypeArgument(instanceTypeName, typeArgumentStart, i, diagnostics));
              typeArgumentStart = i + 1;
            }
            break;
          }
          default:
          {
            if (typeArgumentStart == -1)
            {
              typeArgumentStart = i;
            }
            break;
          }
        }
      }
      result.add(handleTypeArgument(instanceTypeName, typeArgumentStart, end, diagnostics));
      return result;
    }

    /**
     * A well formed type argument must denote a valid Java type argument.
     * It may start with a "?"
     * which may be optionally followed by the keyword "extends" or "super"
     * which in turn, when present, must be followed by a
     * {@link #handleInstanceTypeName(char[], int, int, DiagnosticChain) well formed type instance name}.
     * White space before the keyword is optional but at least one space character is expected after the keyword.
     * Otherwise, the whole string must be a well formed instance type name.
     * @param instanceTypeName the instance type name in question.
     * @param start the start of the characters under consideration.
     * @param end the end of the characters under consideration.
     * @param diagnostics the target in which to accumulate diagnostics.
     * @return the generic type representing the type argument.
     */
    protected EGenericType handleTypeArgument(char [] instanceTypeName, int start, int end, DiagnosticChain diagnostics)
    {
      EGenericType eGenericType = null;
      int firstNonWhiteSpaceIndex = start;
      LOOP:
      for (int i = start; i < end; i = Character.offsetByCodePoints(instanceTypeName, 0, instanceTypeName.length, i, 1))
      {
        int codePoint = Character.codePointAt(instanceTypeName, i);
        switch (codePoint)
        {
          case '?':
          {
            if (eGenericType == null)
            {
              eGenericType = EcoreFactory.eINSTANCE.createEGenericType();
              break;
            }
            else
            {
              report
                (diagnostics, 
                 "_UI_EClassifierInstanceTypeNameTooManyQuestionMarks_diagnostic", 
                 new Object [] { i }, 
                 i);
              break LOOP;
            }
          }
          case 'e':
          {
            if (eGenericType != null)
            {
              if (i + 7 < end &&
                    instanceTypeName[i + 1] == 'x' &&
                    instanceTypeName[i + 2] == 't' &&
                    instanceTypeName[i + 3] == 'e' &&
                    instanceTypeName[i + 4] == 'n' &&
                    instanceTypeName[i + 5] == 'd' &&
                    instanceTypeName[i + 6] == 's' &&
                    Character.isWhitespace(Character.codePointAt(instanceTypeName, i + 7)))
              {
                EGenericType eUpperBound = 
                  handleInstanceTypeName
                    (instanceTypeName, Character.offsetByCodePoints(instanceTypeName, 0, instanceTypeName.length, i + 6, 1), end, diagnostics);
                eGenericType.setEUpperBound(eUpperBound);
              }
              else
              {
                report
                  (diagnostics, 
                   "_UI_EClassifierInstanceTypeNameExpectingExtends_diagnostic", 
                   new Object [] { i }, 
                   i);
              }
            }
            else
            {
              eGenericType = handleInstanceTypeName(instanceTypeName, start, end, diagnostics);
            }
            break LOOP;
          }
          case 's':
          {
            if (eGenericType != null)
            {
              if (i + 5 < end &&
                    instanceTypeName[i + 1] == 'u' &&
                    instanceTypeName[i + 2] == 'p' &&
                    instanceTypeName[i + 3] == 'e' &&
                    instanceTypeName[i + 4] == 'r' &&
                    Character.isWhitespace(Character.codePointAt(instanceTypeName, i + 5)))
              {
                EGenericType eLowerBound = 
                  handleInstanceTypeName
                    (instanceTypeName, Character.offsetByCodePoints(instanceTypeName, 0, instanceTypeName.length, i + 4, 1), end, diagnostics);
                eGenericType.setELowerBound(eLowerBound);
              }
              else
              {
                report
                  (diagnostics, 
                   "_UI_EClassifierInstanceTypeNameExpectingSuper_diagnostic", 
                   new Object [] { i },
                   i);
              }
            }
            else
            {
              eGenericType = handleInstanceTypeName(instanceTypeName, start, end, diagnostics);
            }
            break LOOP;
          }
          default:
          {
            if (Character.isWhitespace(codePoint))
            {
              break;
            }
            else if (eGenericType != null)
            {
              report
                (diagnostics, 
                 "_UI_EClassifierInstanceTypeNameExpectingExtendsOrSuper_diagnostic", 
                 new Object [] { i }, 
                 i);
              break LOOP;
            }
            else
            {
              firstNonWhiteSpaceIndex = i;
              eGenericType = handleInstanceTypeName(instanceTypeName, i, end, diagnostics);
              break LOOP;
            }
          } 
        }
      }
      if (eGenericType == null)
      {
        eGenericType = EcoreFactory.eINSTANCE.createEGenericType();
        report
          (diagnostics, 
           "_UI_EClassifierInstanceTypeNameTypeArgumentExpected_diagnostic", 
           new Object [] { firstNonWhiteSpaceIndex }, 
           firstNonWhiteSpaceIndex);
      }
      return eGenericType;
    }

    /**
     * Well formed type parameters must syntactically denote a comma separated sequence of
     * {@link #handleTypeParameter(char[], int, int, DiagnosticChain) well formed type parameters} delimited by "&lt;>".
     * Whitespace before or after parameters is ignored.
     * @param typeParameters the type parameters question.
     * @param start the start of the characters under consideration.
     * @param end the end of the characters under consideration.
     * @param diagnostics the target in which to accumulate diagnostics.
     * @return a list of type parameters.
     */
    protected List<ETypeParameter> handleTypeParameters(char [] typeParameters, int start, int end, DiagnosticChain diagnostics)
    {
      List<ETypeParameter> result = new ArrayList<ETypeParameter>();
      int depth = 0;
      int typeArgumentStart = -1;
      for (int i = start; i < end; i = Character.offsetByCodePoints(typeParameters, 0, typeParameters.length, i, 1))
      {
        int codePoint = Character.codePointAt(typeParameters, i);
        switch (codePoint)
        {
          case '<':
          {
            ++depth;
            break;
          }
          case '>':
          {
            if (--depth == 0)
            {
              result.add(handleTypeParameter(typeParameters, typeArgumentStart, i, diagnostics));
            }
            break;
          }
          case ',':
          {
            if (depth == 1)
            {
              result.add(handleTypeParameter(typeParameters, typeArgumentStart, i, diagnostics));
              typeArgumentStart = i + 1;
            }
            break;
          }
          default:
          {
            if (typeArgumentStart == -1)
            {
              typeArgumentStart = i;
            }
            break;
          }
        }
      }
      if (depth != 0)
      {
        report
          (diagnostics, 
           "_UI_EClassifierInstanceTypeNameUnterminatedAngleBracket_diagnostic", 
           new Object [] { start }, 
           start);
      }
      return result;
    }

    /**
     * A well formed type parameter must denote a valid Java type parameter.
     * It must start with a well formed java identifier
     * which may be optionally followed by the keyword "extends"
     * which in turn, when present, must be followed by 
     * one or more '&amp;' separated {@link #handleTypeArgument(char[], int, int, DiagnosticChain) well formed type arguments} representing the bounds.
     * White space before the keyword is optional but at least one space character is expected after the keyword.
     * @param typeParameters the instance type name in question.
     * @param start the start of the characters under consideration.
     * @param end the end of the characters under consideration.
     * @param diagnostics the target in which to accumulate diagnostics.
     * @return the type parameter.
     */
    protected ETypeParameter handleTypeParameter(char [] typeParameters, int start, int end, DiagnosticChain diagnostics)
    {
      ETypeParameter eTypeParameter = EcoreFactory.eINSTANCE.createETypeParameter();
      int identifierStart = -1;
      int identifierLast = -1;
      boolean identifierDone = false;
      LOOP:
      for (int i = start; i < end; i = Character.offsetByCodePoints(typeParameters, 0, typeParameters.length, i, 1))
      {
        int codePoint = Character.codePointAt(typeParameters, i);
        if (Character.isWhitespace(codePoint))
        {
          if (identifierStart != -1)
          {
            identifierDone = true;
          }
        }
        else if (identifierDone)
        {
          if (codePoint == 'e' && 
               i + 7 < end &&
               typeParameters[i + 1] == 'x' &&
               typeParameters[i + 2] == 't' &&
               typeParameters[i + 3] == 'e' &&
               typeParameters[i + 4] == 'n' &&
               typeParameters[i + 5] == 'd' &&
               typeParameters[i + 6] == 's' &&
               Character.isWhitespace(Character.codePointAt(typeParameters, i + 7)))
          {
            i += 7;
            int boundStart = i;
            while (i < end)
            {
              char character = typeParameters[i];
              if (character == '&')
              {
                EGenericType eBound = handleInstanceTypeName(typeParameters, boundStart, i, diagnostics);
                eTypeParameter.getEBounds().add(eBound);
                boundStart = i + 1;
              }
              ++i;
            }
            EGenericType eBound = handleInstanceTypeName(typeParameters, boundStart, i, diagnostics);
            eTypeParameter.getEBounds().add(eBound);
          }
          else
          {
            report
              (diagnostics, 
               "_UI_EClassifierInstanceTypeNameExpectingExtends_diagnostic", 
               new Object [] { i }, 
               i);
          }
          break LOOP;
        }
        else if (identifierStart != -1 ? isIdentifierPart(codePoint) : isIdentifierStart(codePoint))
        {
          if (identifierStart == -1)
          {
            identifierStart = i;
          }
          identifierLast = i;
        }
        else
        {
          report
            (diagnostics, 
             "_UI_EClassifierInstanceTypeNameUnexpectedCharacter_diagnostic", 
             new Object [] { i, new String(Character.toChars(codePoint)) }, 
             i);
          break LOOP;
        }
      }
      
      if (identifierLast == -1)
      {
        report
          (diagnostics, 
            "_UI_EClassifierInstanceTypeNameExpectingIdentifier_diagnostic", 
            new Object [] { end }, 
            end);
      }
      else
      {
        eTypeParameter.setName(new String(typeParameters, identifierStart, identifierLast - identifierStart + 1));
      }
      return eTypeParameter;
    }

    /**
     * Creates a new {@link BasicDiagnostic#BasicDiagnostic(int, String, int, String, Object[]) basic diagnostic}.
     * It calls {@link #getString(String, Object[])} for the message substitution.
     * @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
     * @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)
    {
      String message = getString(messageKey, messageSubstitutions);
      return new BasicDiagnostic(severity, source, code, message, data);
    }

    /**
     * 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)
    {
      ResourceLocator resourceLocator = getResourceLocator();
      return substitutions == null ? resourceLocator.getString(key) : resourceLocator.getString(key, substitutions);
    }

    /**
     * Returns the resource locator for {@link #getString(String, Object[]) fetching} messages.
     * @return the resource locator for fetching messages.
     * @since 2.4
     */
    protected ResourceLocator getResourceLocator()
    {
      return EcorePlugin.INSTANCE;
    }
  }

  /**
   * Creates a new diagnostic for a problem at the given index.
   * @param diagnostics the target for the new diagnostic.
   * @param key the key for the message.
   * @param substitutions the substitutions for the key; <code>null</code> if there are no substitutions.
   * @param index the index at which the problem occurred.
   * @see EGenericTypeBuilder#report(DiagnosticChain, String, Object[], int)
   * @since 2.4
   */
  protected void report(DiagnosticChain diagnostics, String key, Object[] substitutions, int index, Map<Object, Object> context)
  {
    if (diagnostics != null)
    {
      diagnostics.add
        (new BasicDiagnostic
           (Diagnostic.ERROR,
            DIAGNOSTIC_SOURCE,
            WELL_FORMED_INSTANCE_TYPE_NAME,
            getString(key, substitutions),
            new Object [] { index }));
    }
  }

} //EcoreValidator
