For simple applications, or cases where only a few constraints are required, possibly to
extend those already provided by another plug-in, the
static constraint provider works well. However, this
approach is limited by its verbosity and the load on the Eclipse Platform's extension
registry. Like their static counterparts, though, these providers are also declared on the
org.eclipse.emf.validation.constraintProviders
extension point.
A more flexible approach is the dynamic constraint provider. Many applications naturally
have their own ways of defining constraints, and the provider is required only as an integrator,
to make them available to the EMF Validation Framework.
[
as SVG]
A dynamic constraint provider extends the
AbstractConstraintProvider
class and extends the setInitializationData() method to initialize
its constraints. This consists of constructing instances of the
AbstractConstraintDescriptor
class, as appropriate, and creating a suitable subclass of the
ModelConstraint
class to implement the constraints.
Creating Constraints
The AbstractConstraintProvider class provides two convenience
methods for creating constraints based on
constraint languages
available in the system. The createModelConstraint(IConstraintDescriptor)
method looks up the language provider and delegates to it to create a constraint with the
supplied descriptor, which must specify the appropriate language and whatever else is
required by that language (such as class name for Java or body expression for OCL).
The createModelConstraintProxy(IConstraintDescriptor) method does
much the same, except that it returns a proxy object wrapping the descriptor that will
lazily instantiate the concrete constraint implementation when it is actually called upon
to validate. This supports deferral of potentially expensive initialization, such as
parsing OCL or performing I/O.
The org.eclipse.emf.validation.examples.ocl example plug-in
includes a constraint provider implementation that loads OCL constraints from
*.ocl files. The declaration of an instance of this provider
looks like:
<extension
point="org.eclipse.emf.validation.constraintProviders"
id="oclProvider">
<!-- Custom constraint provider using OCL documents -->
<constraintProvider
class="org.eclipse.emf.validation.examples.ocl.OCLConstraintProvider"
category="Constraints from an OCL Document">
<package namespaceUri="https:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0"/>
<ocl path="constraints/library.ocl"/>
</constraintProvider>
</extension>
As we can see, the constraint provider declares a class instead of using the default
XML-based implementation for static constraint definitions. As with the static provider,
this example declares the namespace(s) of the models for which it provides constraints.
The difference is in the features offered by this particular implementation: a
category element providing a localized name for the category in
which the constraints will be grouped (because OCL, the language, does not have a notion of
categorization) and an <ocl> element that identifies an
file containing the OCL constraints.
The implementation of this provider extends the setInitializationData()
method to parse the OCL document and encapsulate its invariant constraints in
OCLConstraints:
private void parseConstraints(Category category, String namespace, InputStream input)
throws ParserException {
OCLInput oclInput = new OCLInput(input);
OCL ocl = OCL.newInstance();
for (Constraint constraint : ocl.parse(oclInput)) {
if (isInvariant(constraint)) {
// only add invariant constraints for validation
addConstraint(category, namespace, ocl, constraint);
}
}
}
private void addConstraint(Category category, String namespace, OCL ocl, Constraint constraint) {
@SuppressWarnings("unchecked")
Collection<OCLConstraint> constraints = getConstraints();
OCLConstraintDescriptor desc = new OCLConstraintDescriptor(
namespace, constraint, constraints.size() + 1);
if (category != null) {
category.addConstraint(desc);
}
constraints.add(new OCLConstraint(desc, ocl));
}
The OCLConstraint implementation basically just delegates to the
invariant Constraint object parsed from the file. So does the
OCLConstraintDescriptor, to some degree: it delegates the
target metaclass to the constraint's context classifier, its description to the body
expression, etc. Because this example defines its own constraint implementation, not
delegating through the language mechanism to the framework, it does not use the superclass's
createModelConstraintProxy() method to create constraints.
Copyright (c) 2000, 2007 IBM Corporation and others. All Rights Reserved.