You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Next »

Validation and verification are important activities when working with models. Validation means checking external consistency, i.e. that a model corresponds to what it models (usually the real world), whereas verification means checking internal consistency, i.e. that the model isn't contradicting itself. Validation in Ecore relies on capturing knowledge about a domain in the form of constraints, so that you can check that an actual object structure that conforms to a model, also satisfies additional constraints in the domain.

Introduction

Suppose you are modelling an organisation with organisational units (OrgUnit), employees (Person) and roles (Role), and you want to capture the fact that people names can only have letters, spaces and dashes (-), and all OrgUnit should have a manager, i.e. an employee with a role labeled 'manager'. The first rule can be checked by hand-editing the setter-method for the name, but it may be better to somehow indicate that a rules is violated, rather than throwing an exception. The second rule can be easily coded, but it is more difficult to ensure the code is always run when relevant object properties are changed, since several objects and properties are involved. A related problem is how to handle step-wise modelling, since the second rule necessarily will be violated while the model is built, it doesn't make sense to consider it an error that should be prevented. Instead, you can check it at a point when you consider yourself done.

As mentioned in the Ecore page, an Ecore model can be thought of as a way of constraining what objects structures are legal. By using types and multiplicity you can constrain what objects can be linked and how many, but there are still many constraints that cannot be captured with the concepts available in Ecore. To support such constraints, like the ones above, Ecore provides a mechanism for validation that supports both hand-written Java code and interpreted queries using languages like OCL. Ecore's mechanism relies on separating constraints from the checks that are part of the core model and enforced in the generated code. A validator object (EValidator instance) is created and is asked to validate all constraints for a particular object tree, and so-called diagnostic objects report any violations. The standard editors use this mechanism, and mark all invalid objects with a red (error) or yellow (warning) marker, depending on the severity.

Implementing constraints

Ecore supports ways of implementing constraints, Java code in generated validation methods, and interpreted expressions written in one of many supported languages.

Constraints implemented in Java code

The Java code variant relies on genmodel's ability to generate a validator subclass with methods for each constraint. Adding such a constraint is done in three steps:

Step 1: Add an EAnnotation to the appropriate EClass.

Right-click on the EClass in the editor and add an EAnnotation. Set the source attribute to http://www.eclipse.org/emf/2002/Ecore. Then add a key/value pair, with constraints as the key and the logical name of the constraint (a valid Java name) as the value. If you need to add several constraints, separate their names with a space.

Step 2: Generate code and locate the validation method stub(s)

Genmodel will generate an EValidator subclass in the util package with one method for each constraints (if there are any) named validator_<constraint name>. The method body contains template code for adding a diagnostic for a violated constraint with ERROR severity. The condition is initially false and needs to be replaced by the real constraint logic. An example of the generated stub is shown right.

 

Step 3: Implement the constraint logic in Java

The false condition has been replaced by a call to the hasOnlyNameCharacters helper method. You may also lower the severity if the constraint is more of a suggestion. Notice how NOT is added after @generated, to indicate that we've change generated code. This will prevent the code from being overwritten if the class is regenerated.

	/**
	 * Validates the nameCharacters constraint of '<em>Person</em>'.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated NOT
	 */

	public boolean validatePerson_nameCharacters(Person person, ...) {
		if (! hasOnlyNameCharacters(person.getName())) {
			if (diagnostics != null) {
				...
			}
			return false;
		}
		return true;
	}

	private boolean hasOnlyNameCharacters(String name) {
		for (int i = 0; i < name.length(); i++) {
			char c = name.charAt(i);
			if (! (Character.isLetter(c) || c == ' ' || c == '-')) {
				return false;
			}
		}
		return true;
	}

 

Interpreted constraints

 

  • No labels