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.
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="http:///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.