summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2012-03-12 11:58:03 (EDT)
committer Kenn Hussey2012-03-12 11:58:03 (EDT)
commit8fac4dcf8c3970f1f1a270d706f8c127b421785f (patch)
tree2dd01860c7803bf4466fb39de3a94d2dc9e10945
parent16c3b4619945ffd2cf91d7d81e0b793ccefd3646 (diff)
downloadorg.eclipse.uml2-8fac4dcf8c3970f1f1a270d706f8c127b421785f.zip
org.eclipse.uml2-8fac4dcf8c3970f1f1a270d706f8c127b421785f.tar.gz
org.eclipse.uml2-8fac4dcf8c3970f1f1a270d706f8c127b421785f.tar.bz2
[373643] Adding dynamic provider for UML2 validation constraints.
-rw-r--r--plugins/org.eclipse.uml2.uml/META-INF/MANIFEST.MF6
-rw-r--r--plugins/org.eclipse.uml2.uml/plugin.properties7
-rw-r--r--plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingConstraintDescriptor.java116
-rw-r--r--plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingConstraintProvider.java245
-rw-r--r--plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/DelegatingModelConstraint.java196
-rw-r--r--plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/validation/IEValidatorProvider.java65
-rw-r--r--tests/org.eclipse.uml2.uml.tests/META-INF/MANIFEST.MF2
-rw-r--r--tests/org.eclipse.uml2.uml.tests/build.properties5
-rw-r--r--tests/org.eclipse.uml2.uml.tests/plugin.xml47
-rw-r--r--tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/tests/UMLAllTests.java9
-rw-r--r--tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/DelegatingConstraintProviderTest.java185
-rw-r--r--tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/TestClientContextSelector.java43
-rw-r--r--tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/validation/tests/UMLValidationTests.java66
13 files changed, 984 insertions, 8 deletions
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 @@ Export-Package: org.eclipse.uml2.uml,
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_AddVariableValueAction_SingleInputPin_diagnostic = Add variable value actio
_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 @@ public class UMLAllTests
/**
* <!-- 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