[373643] Adding dynamic provider for UML2 validation constraints.
diff --git a/plugins/org.eclipse.uml2.uml/META-INF/MANIFEST.MF b/plugins/org.eclipse.uml2.uml/META-INF/MANIFEST.MF
index 9bb3fa6..e721e38 100644
--- a/plugins/org.eclipse.uml2.uml/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.uml2.uml/META-INF/MANIFEST.MF
@@ -13,12 +13,14 @@
  org.eclipse.uml2.uml.internal.operations;x-internal:=true,
  org.eclipse.uml2.uml.internal.resource;x-internal:=true,
  org.eclipse.uml2.uml.resource,
- org.eclipse.uml2.uml.util
+ org.eclipse.uml2.uml.util,
+ org.eclipse.uml2.uml.validation
 Require-Bundle: org.eclipse.core.runtime,
  org.eclipse.emf.ecore;visibility:=reexport,
  org.eclipse.emf.ecore.xmi;visibility:=reexport,
  org.eclipse.uml2.common;visibility:=reexport,
  org.eclipse.uml2.types;visibility:=reexport,
- org.eclipse.emf.mapping.ecore2xml
+ org.eclipse.emf.mapping.ecore2xml,
+ org.eclipse.emf.validation;resolution:=optional;visibility:=reexport
 Eclipse-LazyStart: true
 Bundle-ActivationPolicy: lazy
diff --git a/plugins/org.eclipse.uml2.uml/plugin.properties b/plugins/org.eclipse.uml2.uml/plugin.properties
index 1528680..e0baee3 100644
--- a/plugins/org.eclipse.uml2.uml/plugin.properties
+++ b/plugins/org.eclipse.uml2.uml/plugin.properties
@@ -8,6 +8,7 @@
 #   IBM - initial API and implementation
 #   Kenn Hussey (Embarcadero Technologies) - 156879, 215488, 213218, 204200
 #   Kenn Hussey (CEA) - 327039, 351774, 373709
+#   Christian W. Damus (CEA) - 373643
 #
 
 # NLS_MESSAGEFORMAT_VAR
@@ -247,3 +248,9 @@
 
 _UI_AssociationClass_CannotBeDefined_diagnostic = Association class ''{0}'' cannot be defined between itself and something else.
 _UI_AssociationClass_DisjointAttributesEnds_diagnostic = The owned attributes and owned ends of association class ''{0}'' are not disjoint.
+
+_UI_Validation_constraintName_ = {0}: {1}
+_UI_Validation_constraintDesc = The modeled constraint ''{0}''.
+_UI_Validation_violation_ = The constraint ''{0}'' is not satisfied.
+_UI_Validation_runtimeError = Delegated validator operation failed with a run-time error: {0}
+_UI_Validation_linkageError = Failed to invoke reflective constraint delegation: {0}
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingConstraintDescriptor.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingConstraintDescriptor.java
new file mode 100644
index 0000000..559df69
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingConstraintDescriptor.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2012 CEA and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - initial API and implementation
+ */
+package org.eclipse.uml2.uml.validation;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.validation.model.ConstraintSeverity;
+import org.eclipse.emf.validation.model.EvaluationMode;
+import org.eclipse.emf.validation.service.AbstractConstraintDescriptor;
+import org.eclipse.uml2.uml.UMLPlugin;
+
+/**
+ * Descriptor of a constraint that delegates to an {@link EPackage}'s
+ * constraints via its generated {@link EValidator}.
+ */
+class DelegatingConstraintDescriptor
+		extends AbstractConstraintDescriptor {
+
+	private final String namespace;
+
+	private final EClass target;
+
+	private final String id;
+
+	private final String name;
+
+	/**
+	 * Initializes me with the {@code EClass} that I constrain.
+	 * 
+	 * @param a
+	 *            namespace in which to define the constraints (e.g.,
+	 *            {@code "org.eclipse.uml2.uml"})
+	 * @param target
+	 *            my target model class
+	 * @param name
+	 *            my name, from the model
+	 */
+	DelegatingConstraintDescriptor(String namespace, EClass target, String name) {
+		this.namespace = namespace;
+		this.target = target;
+		this.name = UMLPlugin.INSTANCE.getString(
+			"_UI_Validation_constraintName_", //$NON-NLS-1$
+			new Object[]{target.getName(), name});
+
+		StringBuilder buf = new StringBuilder();
+		buf.append(namespace);
+		buf.append('.').append(target.getEPackage().getName()).append('.')
+			.append(target.getName());
+		buf.append('.').append(name);
+		this.id = buf.toString();
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public String getPluginId() {
+		return namespace;
+	}
+
+	public String getDescription() {
+		return UMLPlugin.INSTANCE.getString("_UI_Validation_constraintDesc_", //$NON-NLS-1$
+			new Object[]{getName()});
+	}
+
+	public ConstraintSeverity getSeverity() {
+		// in the UML metamodel, constraints generally are warnings
+		return ConstraintSeverity.WARNING;
+	}
+
+	public int getStatusCode() {
+		return 0; // constraints determine their own codes
+	}
+
+	public EvaluationMode<?> getEvaluationMode() {
+		// it is not appropriate to try to invoke EValidator constraints in
+		// Batch mode
+		return EvaluationMode.BATCH;
+	}
+
+	public boolean targetsTypeOf(EObject eObject) {
+		return target.isInstance(eObject);
+	}
+
+	public boolean targetsEvent(Notification notification) {
+		// live mode is not supported
+		return false;
+	}
+
+	public String getMessagePattern() {
+		return UMLPlugin.INSTANCE.getString("_UI_Validation_violation_", //$NON-NLS-1$
+			new Object[]{getName()});
+	}
+
+	public String getBody() {
+		// delegated constraints have nobody (har, har)
+		return null;
+	}
+
+	EClass getTarget() {
+		return target;
+	}
+}
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingConstraintProvider.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingConstraintProvider.java
new file mode 100644
index 0000000..931b4f9
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingConstraintProvider.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2012 CEA and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - initial API and implementation
+ */
+package org.eclipse.uml2.uml.validation;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.validation.model.Category;
+import org.eclipse.emf.validation.model.CategoryManager;
+import org.eclipse.emf.validation.model.IModelConstraint;
+import org.eclipse.emf.validation.service.AbstractConstraintProvider;
+import org.eclipse.emf.validation.service.ConstraintExistsException;
+import org.eclipse.emf.validation.service.IConstraintDescriptor;
+import org.eclipse.uml2.common.util.UML2Util;
+import org.eclipse.uml2.uml.UMLPlugin;
+
+/**
+ * A provider of constraints that delegate to an {@link EPackage}'s constraints
+ * via its generated {@link EValidator}.
+ */
+public class DelegatingConstraintProvider
+		extends AbstractConstraintProvider {
+
+	private static final String E_CATEGORY = "category"; //$NON-NLS-1$
+
+	private static final String A_PATH = "path"; //$NON-NLS-1$
+
+	private static final String E_EVALIDATOR_PROVIDER = "eValidatorProvider"; //$NON-NLS-1$
+
+	private static final String A_CLASS = "class"; //$NON-NLS-1$
+
+	/**
+	 * Initializes me.
+	 */
+	public DelegatingConstraintProvider() {
+		super();
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data)
+			throws CoreException {
+
+		super.setInitializationData(config, propertyName, data);
+
+		// first, grab the categories that I'll be assigning to my constraints
+		final Set<Category> categories = getCategories(config);
+
+		// get an EValidator provider
+		IEValidatorProvider validatorProvider = getEValidatorProvider(config);
+
+		// then find the constraints that I need to adapt
+		for (String next : getNamespaceUris()) {
+			// find the EValidator for this package
+			EPackage epackage = EPackage.Registry.INSTANCE.getEPackage(next);
+
+			if (epackage == null) {
+				UMLPlugin.INSTANCE
+					.log(new Status(
+						IStatus.WARNING,
+						UMLPlugin.INSTANCE.getSymbolicName(),
+						"No such EPackage available for model validation: " + next)); //$NON-NLS-1$
+			} else {
+				EValidator validator = validatorProvider
+					.getEValidator(epackage);
+				if (validator == null) {
+					UMLPlugin.INSTANCE
+						.log(new Status(
+							IStatus.WARNING,
+							UMLPlugin.INSTANCE.getSymbolicName(),
+							"No generated validator available for package: " + next)); //$NON-NLS-1$
+				} else {
+					try {
+						Iterable<? extends IModelConstraint> constraints = createConstraints(
+							config.getNamespaceIdentifier(), epackage,
+							validator);
+
+						if (!categories.isEmpty()) {
+							Category[] cats = categories
+								.toArray(new Category[categories.size()]);
+							for (IModelConstraint constraint : constraints) {
+								IConstraintDescriptor desc = constraint
+									.getDescriptor();
+								for (int i = 0; i < cats.length; i++) {
+									desc.addCategory(cats[i]);
+								}
+							}
+						}
+					} catch (ConstraintExistsException e) {
+						throw new CoreException(new Status(IStatus.ERROR,
+							UMLPlugin.INSTANCE.getSymbolicName(),
+							"Failed to register model validation constraints.", //$NON-NLS-1$
+							e));
+					}
+				}
+			}
+		}
+	}
+
+	private Set<Category> getCategories(IConfigurationElement config) {
+		final Set<Category> result = new java.util.HashSet<Category>();
+		for (IConfigurationElement next : config.getChildren(E_CATEGORY)) {
+			String path = next.getAttribute(A_PATH);
+
+			if (!UML2Util.isEmpty(path)) {
+				// if the category doesn't already exist, it is implicitly
+				// created, so
+				// we won't get a null category
+				result.add(CategoryManager.getInstance().getCategory(path));
+			}
+		}
+
+		return result;
+	}
+
+	private IEValidatorProvider getEValidatorProvider(
+			IConfigurationElement config) {
+
+		IEValidatorProvider result = null;
+
+		IConfigurationElement[] vpConfig = config
+			.getChildren(E_EVALIDATOR_PROVIDER);
+		if (vpConfig.length > 0) {
+			Object ext;
+			try {
+				ext = vpConfig[0].createExecutableExtension(A_CLASS);
+				if (ext instanceof IEValidatorProvider) {
+					result = (IEValidatorProvider) ext;
+				}
+			} catch (CoreException e) {
+				UMLPlugin.INSTANCE.log(e.getStatus());
+			}
+		}
+
+		if (result == null) {
+			result = new IEValidatorProvider.Default();
+		}
+
+		return result;
+	}
+
+	private Iterable<? extends IModelConstraint> createConstraints(
+			final String namespace, final EPackage epackage,
+			final EValidator validator)
+			throws ConstraintExistsException {
+
+		final List<IModelConstraint> result = new java.util.ArrayList<IModelConstraint>();
+		final Matcher m = Pattern.compile("validate\\w+_validate(\\w+)") //$NON-NLS-1$
+			.matcher(""); //$NON-NLS-1$
+		final Map<Class<?>, EClass> eclasses = new java.util.HashMap<Class<?>, EClass>();
+
+		for (Method next : validator.getClass().getDeclaredMethods()) {
+			if (Modifier.isPublic(next.getModifiers())) {
+				final Class<?>[] signature = next.getParameterTypes();
+
+				m.reset(next.getName());
+				if (m.matches()
+					&& isConstraintMethod(next.getReturnType(), signature)) {
+					EClass eclass = getEClass(eclasses, epackage, signature[0]);
+
+					// constraint methods could exist for EDataTypes; this
+					// framework doesn't handle them
+					if (eclass != null) {
+						result.add(new DelegatingModelConstraint(namespace,
+							validator, eclass, next));
+					}
+				}
+			}
+		}
+
+		getConstraints().addAll(result);
+		registerConstraints(result);
+
+		return result;
+	}
+
+	private static boolean isConstraintMethod(Class<?> returnType,
+			Class<?>[] parameterTypes) {
+
+		boolean result = false;
+
+		if ((returnType == boolean.class) && (parameterTypes.length == 3)) {
+			result = EObject.class.isAssignableFrom(parameterTypes[0])
+				&& (parameterTypes[1] == DiagnosticChain.class)
+				&& (parameterTypes[2] == Map.class);
+		}
+
+		return result;
+	}
+
+	/**
+	 * Look up an {@link EClass} by instance-class, using a cache for
+	 * performance of repeated queries.
+	 * 
+	 * @param cache
+	 *            a cache of previous look-up results
+	 * @param epackage
+	 *            the epackage in which to find the eclass
+	 * @param interfaceType
+	 *            the Java interface type by which to look up the eclass
+	 * 
+	 * @return the eclass, or {@code null} if not found
+	 */
+	private static EClass getEClass(Map<Class<?>, EClass> cache,
+			EPackage epackage, Class<?> interfaceType) {
+
+		EClass result = cache.get(interfaceType);
+
+		if (result == null) {
+			for (EClassifier next : epackage.getEClassifiers()) {
+				if ((next.getInstanceClass() == interfaceType)
+					&& (next instanceof EClass)) {
+					result = (EClass) next;
+					cache.put(interfaceType, result);
+					break;
+				}
+			}
+		}
+
+		return result;
+	}
+}
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingModelConstraint.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingModelConstraint.java
new file mode 100644
index 0000000..deff6bf
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingModelConstraint.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2012 CEA and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - initial API and implementation
+ */
+package org.eclipse.uml2.uml.validation;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+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.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.validation.IValidationContext;
+import org.eclipse.emf.validation.model.ConstraintStatus;
+import org.eclipse.emf.validation.model.IConstraintStatus;
+import org.eclipse.emf.validation.model.IModelConstraint;
+import org.eclipse.emf.validation.service.IConstraintDescriptor;
+import org.eclipse.uml2.uml.UMLPlugin;
+
+/**
+ * Implementation of a constraint that delegates to an {@link EPackage}'s
+ * constraints via its generated {@link EValidator}.
+ */
+class DelegatingModelConstraint
+		implements IModelConstraint {
+
+	private final IConstraintDescriptor descriptor;
+
+	private final EValidator delegate;
+
+	private final Method constraintMethod;
+
+	/**
+	 * Initializes me.
+	 */
+	DelegatingModelConstraint(String namespace, EValidator delegate,
+			EClass target, Method constraintMethod) {
+		// strip the type-qualifying part off of the validator method name
+		String name = constraintMethod.getName();
+		String expectedPrefix = String.format("validate%s_validate", //$NON-NLS-1$
+			target.getName());
+		if (name.startsWith(expectedPrefix)) {
+			name = name.substring(expectedPrefix.length());
+		}
+
+		this.descriptor = new DelegatingConstraintDescriptor(namespace, target,
+			name);
+		this.delegate = delegate;
+		this.constraintMethod = constraintMethod;
+	}
+
+	public final IConstraintDescriptor getDescriptor() {
+		return descriptor;
+	}
+
+	public IStatus validate(IValidationContext ctx) {
+		IStatus result;
+
+		final ContextAdapter ctxAdapter = ContextAdapter.getInstance(ctx);
+		final BasicDiagnostic diagnostics = ctxAdapter.getDiagnostics();
+		final Map<Object, Object> contextMap = ctxAdapter.getContextMap();
+
+		try {
+			boolean isOK = (Boolean) constraintMethod.invoke(delegate,
+				ctx.getTarget(), diagnostics, contextMap);
+
+			if (isOK) {
+				result = ctx.createSuccessStatus();
+			} else {
+				final int count = diagnostics.getChildren().size();
+
+				switch (count) {
+					case 0 :
+						result = ctx.createFailureStatus(getDescriptor()
+							.getName());
+						break;
+					case 1 :
+						result = toConstraintStatus(ctx, diagnostics
+							.getChildren().get(0));
+						break;
+					default :
+						List<IStatus> statuses = new java.util.ArrayList<IStatus>(
+							diagnostics.getChildren().size());
+						for (Diagnostic next : diagnostics.getChildren()) {
+							statuses.add(toConstraintStatus(ctx, next));
+						}
+						result = ConstraintStatus.createMultiStatus(ctx,
+							statuses);
+						break;
+				}
+			}
+		} catch (InvocationTargetException e) {
+			// disable this constraint in future validation operations
+			ctx.disableCurrentConstraint(e.getTargetException());
+
+			result = ConstraintStatus.createStatus(ctx, ctx.getTarget(), ctx
+				.getResultLocus(), IStatus.WARNING, getDescriptor()
+				.getStatusCode(), UMLPlugin.INSTANCE
+				.getString("_UI_Validation_runtimeError"), //$NON-NLS-1$
+				getDescriptor().getException().getMessage());
+		} catch (Exception e) {
+			// disable this constraint in future validation operations
+			ctx.disableCurrentConstraint(e);
+
+			result = ConstraintStatus.createStatus(ctx, ctx.getTarget(), ctx
+				.getResultLocus(), IStatus.WARNING, getDescriptor()
+				.getStatusCode(), UMLPlugin.INSTANCE
+				.getString("_UI_Validation_linkageError"), //$NON-NLS-1$
+				e.getMessage());
+		}
+
+		return result;
+	}
+
+	private static IConstraintStatus toConstraintStatus(IValidationContext ctx,
+			Diagnostic diagnostic) {
+		final EObject target = ctx.getTarget();
+
+		// collect the "result locus" on which to create problem markers, or
+		// whatever
+		List<EObject> resultLocus = new java.util.ArrayList<EObject>(3);
+		for (Object next : diagnostic.getData()) {
+			if ((next != target) && (next instanceof EObject)) {
+				resultLocus.add((EObject) next);
+			}
+		}
+
+		return ConstraintStatus.createStatus(ctx, target, resultLocus,
+			diagnostic.getSeverity(), diagnostic.getCode(),
+			diagnostic.getMessage());
+	}
+
+	//
+	// Nested types
+	//
+
+	/**
+	 * A translation from the EMF Validation Framework's
+	 * {@link IValidationContext}-based API to EMF's {@link DiagnosticChain}-
+	 * and map-based API. A weak mapping ensures that the same adapters are
+	 * reused as appropriate for any given instance of the validation context.
+	 */
+	private static final class ContextAdapter {
+
+		private static final Map<IValidationContext, ContextAdapter> contextAdapters = new java.util.WeakHashMap<IValidationContext, ContextAdapter>();
+
+		private Map<Object, Object> contextMap = new java.util.HashMap<Object, Object>();
+
+		private BasicDiagnostic diagnostics;
+
+		ContextAdapter() {
+			super();
+		}
+
+		static ContextAdapter getInstance(IValidationContext ctx) {
+			ContextAdapter result = contextAdapters.get(ctx);
+
+			if (result == null) {
+				result = new ContextAdapter();
+				contextAdapters.put(ctx, result);
+			}
+
+			return result;
+		}
+
+		Map<Object, Object> getContextMap() {
+			return contextMap;
+		}
+
+		BasicDiagnostic getDiagnostics() {
+			if ((diagnostics != null) && !diagnostics.getChildren().isEmpty()) {
+				// self-destruct a diagnostic that previously had problems added
+				// to it
+				diagnostics = null;
+			}
+
+			if (diagnostics == null) {
+				diagnostics = new BasicDiagnostic();
+			}
+
+			return diagnostics;
+		}
+	}
+}
diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/IEValidatorProvider.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/IEValidatorProvider.java
new file mode 100644
index 0000000..fb380c0
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/IEValidatorProvider.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012 CEA and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - initial API and implementation
+ */
+package org.eclipse.uml2.uml.validation;
+
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.uml2.uml.UMLPackage;
+import org.eclipse.uml2.uml.util.UMLValidator;
+
+/**
+ * A protocol for package-to-validator mappings.
+ */
+public interface IEValidatorProvider {
+
+	/**
+	 * Obtains an appropriate {@link EValidator} for validation of instances of
+	 * the specified {@code ePackage}.
+	 * 
+	 * @param ePackage
+	 *            a package for which to obtain a validator
+	 * 
+	 * @return a suitable validator, or {@code null} if none could be found
+	 */
+	EValidator getEValidator(EPackage ePackage);
+
+	//
+	// Nested types
+	//
+
+	/**
+	 * The default {@link EValidator} provider uses the validator registry to
+	 * look up whatever validator is there.
+	 */
+	class Default
+			implements IEValidatorProvider {
+
+		public EValidator getEValidator(EPackage ePackage) {
+			return EValidator.Registry.INSTANCE.getEValidator(ePackage);
+		}
+	}
+
+	/**
+	 * The UML {@link EValidator} maps the UML package to the standard UML
+	 * validator. For other packageos, uses the validator registry to look up
+	 * whatever validator is there.
+	 */
+	class UML
+			extends Default {
+
+		@Override
+		public EValidator getEValidator(EPackage ePackage) {
+			return (ePackage == UMLPackage.eINSTANCE)
+				? UMLValidator.INSTANCE
+				: super.getEValidator(ePackage);
+		}
+	}
+}
diff --git a/tests/org.eclipse.uml2.uml.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.uml2.uml.tests/META-INF/MANIFEST.MF
index e400f1f..e11632d 100644
--- a/tests/org.eclipse.uml2.uml.tests/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.uml2.uml.tests/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
-Bundle-SymbolicName: org.eclipse.uml2.uml.tests; singleton:=true
+Bundle-SymbolicName: org.eclipse.uml2.uml.tests;singleton:=true
 Bundle-Version: 4.0.0.qualifier
 Bundle-ClassPath: uml2.uml.tests.jar
 Bundle-Vendor: %providerName
diff --git a/tests/org.eclipse.uml2.uml.tests/build.properties b/tests/org.eclipse.uml2.uml.tests/build.properties
index 28b5baa..6fc17fc 100644
--- a/tests/org.eclipse.uml2.uml.tests/build.properties
+++ b/tests/org.eclipse.uml2.uml.tests/build.properties
@@ -1,4 +1,4 @@
-# Copyright (c) 2005, 2008 IBM Corporation, Embarcadero Technologies, and others.
+# Copyright (c) 2005, 2012 IBM Corporation, Embarcadero Technologies, CEA, and others.
 # All rights reserved.   This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
 # which accompanies this distribution, and is available at
@@ -7,13 +7,14 @@
 # Contributors:
 #   IBM - initial API and implementation
 #   Kenn Hussey (Embarcadero Technologies) - 204200
+#   Christian W. Damus (CEA) - 373643
 #
-# $Id: build.properties,v 1.5 2008/02/19 23:15:54 khussey Exp $
 
 # NLS_MESSAGEFORMAT_VAR
 source.uml2.uml.tests.jar = src/
 output.uml2.uml.tests.jar = bin/
 bin.includes = about.html,\
+               plugin.xml,\
                plugin.properties,\
                test.xml,\
                uml2.uml.tests.jar,\
diff --git a/tests/org.eclipse.uml2.uml.tests/plugin.xml b/tests/org.eclipse.uml2.uml.tests/plugin.xml
new file mode 100644
index 0000000..bdaf994
--- /dev/null
+++ b/tests/org.eclipse.uml2.uml.tests/plugin.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+
+<!--
+ Copyright (c) 2012 CEA and others.
+ All rights reserved.   This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html
+
+ Contributors:
+   Christian W. Damus (CEA) - initial API and implementation
+
+-->
+
+<plugin>
+   <extension
+         point="org.eclipse.emf.validation.constraintProviders">
+      <category
+            id="org.eclipse.uml2.uml.tests"
+            name="UML Test Constraints">
+      </category>
+      <constraintProvider
+            cache="true"
+            class="org.eclipse.uml2.uml.validation.DelegatingConstraintProvider"
+            mode="Batch">
+         <package
+               namespaceUri="http://www.eclipse.org/uml2/4.0.0/UML">
+         </package>
+         <category path="org.eclipse.uml2.uml.tests"/>
+      </constraintProvider>
+   </extension>
+   <extension
+         point="org.eclipse.emf.validation.constraintBindings">
+      <clientContext
+            id="org.eclipse.uml2.uml.tests.clientContext">
+         <selector
+               class="org.eclipse.uml2.uml.validation.tests.TestClientContextSelector">
+         </selector>
+      </clientContext>
+      <binding
+            context="org.eclipse.uml2.uml.tests.clientContext"
+            category="org.eclipse.uml2.uml.tests">
+      </binding>
+   </extension>
+
+</plugin>
diff --git a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/tests/UMLAllTests.java b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/tests/UMLAllTests.java
index 0ef500d..57b9bb1 100644
--- a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/tests/UMLAllTests.java
+++ b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/tests/UMLAllTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 IBM Corporation and others.
+ * Copyright (c) 2005, 2012 IBM Corporation, CEA, and others.
  * All rights reserved.   This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -7,11 +7,13 @@
  *
  * Contributors:
  *   IBM - initial API and implementation
+ *   Christian W. Damus (CEA) - Bug 373643
  *
- * $Id: UMLAllTests.java,v 1.1 2006/02/21 16:32:24 khussey Exp $
  */
 package org.eclipse.uml2.uml.tests;
 
+import org.eclipse.uml2.uml.validation.tests.UMLValidationTests;
+
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
@@ -38,11 +40,12 @@
 	/**
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
-	 * @generated
+	 * @generated NOT
 	 */
 	public static Test suite() {
 		TestSuite suite = new UMLAllTests("UML Tests"); //$NON-NLS-1$
 		suite.addTest(UMLTests.suite());
+		suite.addTest(UMLValidationTests.suite());
 		return suite;
 	}
 
diff --git a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/DelegatingConstraintProviderTest.java b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/DelegatingConstraintProviderTest.java
new file mode 100644
index 0000000..939d22b
--- /dev/null
+++ b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/DelegatingConstraintProviderTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2012 CEA and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - initial API and implementation
+ */
+package org.eclipse.uml2.uml.validation.tests;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.validation.model.Category;
+import org.eclipse.emf.validation.model.CategoryManager;
+import org.eclipse.emf.validation.model.EvaluationMode;
+import org.eclipse.emf.validation.model.IConstraintStatus;
+import org.eclipse.emf.validation.service.IBatchValidator;
+import org.eclipse.emf.validation.service.IConstraintDescriptor;
+import org.eclipse.emf.validation.service.IConstraintFilter;
+import org.eclipse.emf.validation.service.ModelValidationService;
+import org.eclipse.uml2.uml.Actor;
+import org.eclipse.uml2.uml.Component;
+import org.eclipse.uml2.uml.Generalization;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.UMLFactory;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite for the {@link DelegatingConstraintProvider} class and attendant
+ * classes.
+ */
+public class DelegatingConstraintProviderTest
+		extends TestCase {
+
+	/**
+	 * Initializes me with my name.
+	 * 
+	 * @param name
+	 *            my name
+	 */
+	public DelegatingConstraintProviderTest(String name) {
+		super(name);
+	}
+
+	public static Test suite() {
+		return new TestSuite(DelegatingConstraintProviderTest.class,
+			"Delegating constraint provider tests"); //$NON-NLS-1$
+	}
+
+	public void test_constraintsCategorized() {
+		Category testCategory = CategoryManager.getInstance().getCategory(
+			"org.eclipse.uml2.uml.tests"); //$NON-NLS-1$
+
+		boolean found = false;
+		for (IConstraintDescriptor next : testCategory.getConstraints()) {
+			if (next.getClass().getSimpleName()
+				.equals("DelegatingConstraintDescriptor")) { //$NON-NLS-1$
+				found = true;
+				break;
+			}
+		}
+
+		assertTrue(
+			"Didn't find any UML constraints in the test category", found); //$NON-NLS-1$
+	}
+
+	public void test_providedConstraintsRun() {
+		Package package_ = UMLFactory.eINSTANCE.createPackage();
+		Component component = (Component) package_.createOwnedType(
+			"MyComponent", UMLPackage.Literals.COMPONENT); //$NON-NLS-1$
+		Actor user = (Actor) package_.createOwnedType("User", //$NON-NLS-1$
+			UMLPackage.Literals.ACTOR);
+		Generalization generalization = user.createGeneralization(component);
+
+		// actor does not have a name. It must. Only check this constraint
+		IBatchValidator validator = ModelValidationService.getInstance()
+			.newValidator(EvaluationMode.BATCH);
+		validator.addConstraintFilter(new NameFilter("SpecializeType")); //$NON-NLS-1$
+
+		IStatus status = validator.validate(package_);
+
+		assertTrue(
+			"Validation should not have passed.", status.getSeverity() >= IStatus.WARNING); //$NON-NLS-1$
+		assertProblemOn(status, user);
+
+		generalization.setGeneral((Actor) package_.createOwnedType("Sys Admin", //$NON-NLS-1$
+			UMLPackage.Literals.ACTOR));
+		status = validator.validate(package_);
+
+		assertNoProblemOn(status, user);
+	}
+
+	//
+	// Test framework
+	//
+
+	@Override
+	protected void setUp()
+			throws Exception {
+		super.setUp();
+
+		TestClientContextSelector.turnOn();
+
+		// poke the framework to make sure that our provider loads its
+		// constraints
+		ModelValidationService.getInstance().newValidator(EvaluationMode.BATCH)
+			.validate(UMLFactory.eINSTANCE.createPackage());
+	}
+
+	@Override
+	protected void tearDown()
+			throws Exception {
+		TestClientContextSelector.turnOff();
+
+		super.tearDown();
+	}
+
+	IConstraintStatus findStatusOf(IStatus status, EObject object) {
+		IConstraintStatus result = null;
+
+		if (status instanceof IConstraintStatus) {
+			IConstraintStatus candidate = (IConstraintStatus) status;
+
+			if (candidate.getTarget() == object) {
+				result = candidate;
+			}
+		}
+
+		if ((result == null) && status.isMultiStatus()) {
+			for (IStatus next : status.getChildren()) {
+				result = findStatusOf(next, object);
+
+				if (result != null) {
+					break;
+				}
+			}
+		}
+
+		return result;
+	}
+
+	void assertProblemOn(IStatus status, EObject object) {
+		IConstraintStatus specific = findStatusOf(status, object);
+
+		if (specific == null) {
+			fail("No status for object " + object); //$NON-NLS-1$
+		}
+
+		assertFalse("Status is not a problem", specific.isOK()); //$NON-NLS-1$
+	}
+
+	void assertNoProblemOn(IStatus status, EObject object) {
+		IConstraintStatus specific = findStatusOf(status, object);
+
+		if (specific != null) {
+			assertTrue("Status is a problem", specific.isOK()); //$NON-NLS-1$
+		}
+	}
+
+	//
+	// Nested types
+	//
+
+	static class NameFilter
+			implements IConstraintFilter {
+
+		private final Pattern pattern;
+
+		NameFilter(String pattern) {
+			this.pattern = Pattern.compile(pattern);
+		}
+
+		public boolean accept(IConstraintDescriptor constraint, EObject target) {
+			return pattern.matcher(constraint.getName()).find();
+		}
+	}
+}
diff --git a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/TestClientContextSelector.java b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/TestClientContextSelector.java
new file mode 100644
index 0000000..52c893b
--- /dev/null
+++ b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/TestClientContextSelector.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012 CEA and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - initial API and implementation
+ */
+package org.eclipse.uml2.uml.validation.tests;
+
+import org.eclipse.emf.validation.model.IClientSelector;
+import org.eclipse.uml2.uml.Element;
+
+/**
+ * A client-context selector that selects all UML elements while a test is
+ * running.
+ */
+public class TestClientContextSelector
+		implements IClientSelector {
+
+	private static boolean on;
+
+	/**
+	 * Initializes me.
+	 */
+	public TestClientContextSelector() {
+		super();
+	}
+
+	public boolean selects(Object object) {
+		return on && (object instanceof Element);
+	}
+
+	static void turnOn() {
+		on = true;
+	}
+
+	static void turnOff() {
+		on = false;
+	}
+}
diff --git a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/UMLValidationTests.java b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/UMLValidationTests.java
new file mode 100644
index 0000000..c9c967b
--- /dev/null
+++ b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/UMLValidationTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012 CEA and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Christian W. Damus (CEA) - initial API and implementation
+ */
+package org.eclipse.uml2.uml.validation.tests;
+
+import org.eclipse.core.runtime.Platform;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite for the {@code org.eclipse.uml2.uml.validation} package.
+ */
+public class UMLValidationTests
+		extends TestSuite {
+
+	/**
+	 * Initializes me with my name.
+	 * 
+	 * @param name
+	 *            my name
+	 */
+	public UMLValidationTests(String name) {
+		super(name);
+	}
+
+	public static Test suite() {
+		TestSuite result;
+
+		// these tests require an Eclipse instance
+		try {
+			if (new EclipseHelper().isEclipseRunning()) {
+				result = new UMLValidationTests(
+					"UML Validation Constraint Provider Tests"); //$NON-NLS-1$
+				result.addTest(DelegatingConstraintProviderTest.suite());
+			} else {
+				result = new TestSuite(
+					"<UML validation tests require Eclipse to be running>"); //$NON-NLS-1$
+			}
+		} catch (LinkageError e) {
+			// no (or incomplete) Eclipse environment on the classpath
+			result = new TestSuite(
+				"<UML validation tests require an Eclipse instance>"); //$NON-NLS-1$
+		}
+
+		return result;
+	}
+
+	//
+	// Nested types
+	//
+
+	private static class EclipseHelper {
+
+		boolean isEclipseRunning() {
+			return Platform.isRunning();
+		}
+	}
+}
\ No newline at end of file