An alternative to checking constraints with pure Java, is the declarative constraint checking language Check . For details of this language take a look at the Check language reference. We will provide a simple example here.
We start by defining the constraint itself. We create a new file called
checks.chk
in the src
folder of our project. It is important
that this file resides in the classpath! The file has the following
content:
import data; context Attribute ERROR "Names must be more than one char long" : name.length > 1;
This constraint says that for the metaclass
data::Attribute
, we require that the name be more
than one characters long. If this expression evaluates to false, the
error message given before the colon will be reported. A checks file can
contain any number of such constraints. They will be evaluated for all
instances of the respective metaclass.
To show a somewhat more involved constraint example, this one ensures that the names of the attributes have to be unique:
context Entity ERROR "Names of Entity attributes must be unique": attribute.forAll(a1| attribute.notExists(a2| a1 != a2 && a1.name == a2.name ) );
The following piece of XML is the workflow file we have already used above.
<workflow> <property file="workflow.properties"/> .. <component class="org.eclipse.emf.mwe.utils.Reader"> <uri value="platform:/resource/${modelFile}" /> .. </component> </workflow>
After reading the model, we add an additional component, namely the CheckComponent .
<component class="org.eclipse.xtend.check.CheckComponent">
As with the code generator, we have to explain to the checker what meta-meta-model and which metamodel we use.
<metaModel id="mm" class="org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel"> </metaModel>
We then have to provide the checks file. The component tries to
load the file by appending .chk
to the name and
searching the classpath – that is why it has to be located in the
classpath.
<checkFile value="checks"/>
Finally, we have to tell the engine on which model or part of the
model the checks should work. In general, you can use the
<expressionvalue="..."/>
element to define an
arbitrary expression on slot contents. For our purpose, where we want to
use the complete EMF data structure in the model slot, we can use the
shortcut
emfAllChildrenSlot
property, which returns
the complete subtree below the content element of a specific slot,
including the slot content element itself.
<emfAllChildrenSlot value="model"/> </component>
Running the workflow produces an error in case the length of the
name is not greater than one. Again, it makes sense to add the
skipOnError="true"
to those subsequent component
invocations that need to be skipped in case the constraint check found
errors (typically code generators or transformers).