h2(#Validators). Validators


When using the Pivot metamodel, there are two specialized validators available to support integration of OCL in to a larger Ecore environment.

h3(#ValidationCode). Validation Code


Before we describe OCL validation we need to review standard EMF validation.


h4(#GlobalValidation). Static / Global Validation


EMF validation comprises two phases.

The first initialization phase populates the global validation registry @EValidator.Registry.INSTANCE@ with a mapping from an @EPackage@ whose elements need validation to the derived @EValidator@ that will perform the validation. This initialization is typically performed at the end of the @XXXPackageImpl.init()@ auto-generated by genmodel.

bc.. 
EValidator.Registry.INSTANCE.put(myEPackage, myEValidator);	
p. 

For standalone usage, this is executed as a side effect of referencing the model by e.g. @XXXPackage.eINSTANCE@. For IDE usage, the @org.eclipse.emf.ecore.generated_package@ extension point ensures timely initialization. Either way, the initialization normally occurs without any special programming effort.

The second validation phase offers each model element to an appropriate @EValidator@ and accumulates the results as a list of @BasicDiagnostic@. The @Diagnostician@ is often used to orchestrate this using code such as:

bc.. 
Diagnostician diagnostician = Diagnostician.INSTANCE;
Map<Object, Object> context = diagnostician.createDefaultContext();
BasicDiagnostic diagnostics = diagnostician.createDefaultDiagnostic(eObject);
diagnostician.validate(eObject, diagnostics, context);	
p. 


h4(#LocalValidation). Dynamic / Local Validation


An EMF @ResourceSet@ provides a local @EPackage.Registry@ and @Resource.Factory.Registry@ that delegates to the corresponding global registry. This allows an EMF-based application to register the @EPackage@ and @ResourceFactory@ for an application-specific purpose without leaking them to other applications. This also allows the garbage collector to clean up when an application completes.  
Unfortunately EMF provides no corresponding support for a local @EValidator.Registry@. This provides a significant challenge for the OCL tooling where for instance an application may load a Complete OCL document with additional constraints that need validation. These additions should not affect other concurrent or subsequent applications.


h5(#EValidatorRegistrationPre2023-12). OCL EValidator registration pre 2023-12


With only a global validation registry available, the old approach was to install the dynamic contributions into the global registry using a @ComposedEValidator@ to ensure that multiple validators are registered with the appropriate one chosen according to the @ResourceSet@ of the validated @EObject@.

This sort of works, but impairs garbage collection and has given trouble to users attempting to run multiple editors.


h5(#EValidatorRegistrationPost2023-12). OCL EValidator registration post 2023-12


The 2023-12 OCL release introduces a local validation registry using @ValidationRegistryAdapter@ to install a @ValidationRegistryImpl@ as a @ResourceSet@ @Adapter@. It delegates to the global validation registry. A @ComposedEValidator@ may still be used to compose a @CompleteOCLEValidator@ and a regular @EObjectValidator@ but they are @ResourceSet@-specific and so do not impose a GC-lockin via a global facility.

Use of a local validation registry has a significant impact on application code.

It is no longer possible to register OCL validators in some convenient initialization method. Validation Registry initialization, just like Resource Factory initialization cannot occur until the @ResourceSet@ is created.


bc.. 
ValidationRegistryAdapter.getAdapter(myResourceSet)
	.put(myEPackage, myEValidator);
p. 

It is no longer possible to use @Diagnostician.INSTANCE@ to orchestrate validation. The variant constructor with a validation registry argument must be used.


bc.. 
Diagnostician diagnostician = new Diagnostician(
	ValidationRegistryAdapter.getAdapter(myResourceSet));
p. 

Optionally the new @ValidationContext@ may be used in place of the @Map<Object,Object>@ to support the following idiom


bc.. 
ValidationRegistryAdapter validationRegistry =
	ValidationRegistryAdapter.getAdapter(myEObject);
ValidationContext validationContext = new ValidationContext(validationRegistry);
Diagnostician diagnostician = validationContext.getDiagnostician();
Diagnostic diagnostics = diagnostician.validate(myEObject, validationContext);
p. 

If the @Diagnostician@ is unaware of the local validation registry, any validators registered locally will be ignored. An error message is generated in the console log if global registration is attempted.


h3(#OCLValidators). OCL Validators

The OCL project provides a variety of validators.


h4(#OCLinEcoreEObjectValidator). OCLinEcoreEObjectValidator

Unfortunately EMF does not yet (2023-12 at time of writing) support message customization and so it must be activated by explicitly using an EValidator that is aware of the ValidationDelegateExtension extended API. This is available by using the OCLinEcoreEObjectValidator, which you may install globally by:

bc.. 
EValidator.Registry.INSTANCE.put(null, new OCLinEcoreEObjectValidator());
p.  
but much better locally 

bc.. 
ValidationRegistryAdapter.getAdapter(myResourceSet).put(null, new OCLinEcoreEObjectValidator());
p. 

or more selectively by adjusting the inheritance of the Validator class generated by EMF from (for a model of a Company):

bc.. 
import org.eclipse.emf.ecore.util.EObjectValidator;
/*
 * <!-- begin-user-doc --
 * The <b>Validator</b> for the model
 * <!-- end-user-doc --
 * @see company.CompanyPackag
 *
public class CompanyValidator extends EObjectValidator 
p.  
to


bc.. 
import org.eclipse.ocl.xtext.oclinecore.validation.OCLinEcoreEObjectValidator;
/*
 * <!-- begin-user-doc --
 * The <b>Validator</b> for the model
 * <!-- end-user-doc --
 * @see company.CompanyPackag
 * @generated not
 *
public class CompanyValidator extends OCLinEcoreEObjectValidator 
p. 
Note the *@generated not* that indicates that the class interface is manually defined. Do not use *@generated NOT* since that indicates that the whole class is manually defined.

h4(#CompleteOCLEObjectValidator). CompleteOCLEObjectValidator

The CompleteOCLEObjectValidator is used to enable Complete OCL documents to participate in the validation processing of an Xtext editor.

The APIs for merging Complete OCL and Ecore as intermediate Pivots and then migrating the Pivot back to Ecore are experimental.


