Jump to: navigation, search

EMFIncQuery/UserDocumentation/Validation

EMF-IncQuery Validation Framework

EMF-IncQuery provides facilities to create validation rules based on the pattern language of the framework. These rules can be evaluated on various EMF instance models and upon violations of constraints, markers are automatically created in the Eclipse Problems View.

Example use case

The following scenario describes and illustrates the way to use the framework for validation purposes (see also the BPMN example):

  1. Create an EMF-IncQuery project with some patterns
  2. Annotate some pattern with the @Constraint annotation - these will be the constraints. In particular, these patterns will be treated as queries that find the violations of the contraint. EMFIncQuery Validation 1.png
  3. Add the generated .validation project to your run configuration (along with the base EMF-IncQuery plug-in)
  4. Initialize the validation framework on some instance model; use the UI context menu on an EMF editor to do so.
  5. Upon constraint violation markers will be placed in the Problems view. Note that the markers are data-bound to corresponding model elements and the labels will be automatically refreshed (when the model changes). EMFIncQuery Validation 2.png

Annotations

The @Constraint annotation can be used to mark an eiq pattern as a validation rule. If the framework finds at least one pattern with such annotation, an additional .validation project will be generated. This project will be used by the validation framework later in your runtime Eclipse configuration.

Annotation parameters

  • location: The location of constraint represents the pattern parameter (the object) the constraint violation needs to be attached to.
  • message: The message to display when the constraint violation is found. The message may refer the parameter variables between $ symbols, or their EMF features, such as in $Param1.name$.
  • severity: "warning" or "error"
  • targetEditorId: An Eclipse editor ID where the validation framework should register itself to the context menu. Use "*" as a wildcard if the constraint should be used always when validation is started.

Generated validation plug-in

The generated .validation project will create a subclass of org.eclipse.incquery.validation.runtime.Constraint for each one of the patterns annotated with @Constraint.

Example and useful resources

  • Please see the BPMN example which demonstrates the usage of the @Constraint annotation.
  • The org.eclipse.incquery.validation.runtime.ConstraintAdapter and org.eclipse.incquery.validation.runtime.ConstraintViolation classes demonstrate the usage of the generated validation code inside the validation framework.

ConstraintAdapter and ConstraintViolation highlights

The validation framework collects all of the Constraints that applies to the constraint extension point schema (defined under org.eclipse.incquery.validation.runtime/schema/constraint.exsd). These constraints are initialized on the loaded instance models and upon constraint violation an appropriate error marker is placed in the runtime Eclipse's Problems View.

First for each collected constraint and instance model a ConstraintAdapter is created which will maintain the match set of the pattern (annotated with @Constraint); these matches are constraint violations, that the user needs to be informed about. For each match of the pattern a ConstraintViolation is instantiated, which is responsible for marker creation/update/deletion.

The ConstraintViolation class uses data binding facilities to register the appropriate callback methods on the location objects of the Constraint, this will result in marker text update when an attribute of some location object is modified.

New validation framework in EMF-IncQuery 1.0.0

Based on the work of Bálint Lóránd, we have a new validation framework that provides a more generic API than simply creating Eclipse problem markers. This new framework has a validation specific API with concepts like constraints and violations, while also significantly increases the descriptive power of the @Constraint annotation by introducing keys and symmetric parameters.

Main concepts

Constraint specification

A constraint specification represents a well-formedness or structural validation rule that is specified with concepts from metamodels and can be evaluated over instance models.

E.g. a constraint specification is "A terminated data port cannot be the end of a port connection", where "terminated", "data port", "port connection" and "connection end" are concepts in the metamodel.

The constraint specification contains:

  • the converting mechanism for creating the location information for a violation
  • the format message that is used to create the message of a violation
  • the severity level (e.g. error, warning)

When constraint specifications are represented by EMF-IncQuery patterns, the corresponding query specification is stored.

Constraint

We differentiate between Constraint Specification that represents the validation rule and Constraint that represents the instantiation of a constraint specification on a validation engine.

Each constraint stores:

  • its specification
  • validation engine

It provides capabilities for:

  • listing the set of violations
  • registering listeners for notifications on the changes in the violation set and other events related to the life cycle of the constraint.

For constraints specified by EMF-IncQuery patterns, the matcher is stored.

Violation

A violation is set of model elements in an instance model that satisfy the specification of a constraint.

E.g. for the above constraint, a violation is a port P which is terminated and a port connection PC with "PC.end = P".

Each violation has:

  • a corresponding constraint
  • a location (one or more model elements that are relevant for the violation (e.g. the port and the port connection in the example)
  • a formatted message.

The violation should provide capabilities for

  • registering listeners for notifications on life cycle events, e.g. a change in the message.

For violation of constraints from EMF-IncQuery patterns, the match is also stored.

Validation Engine

A validation engine is responsible for managing the constraints existing in the scope of an EMF-IncQuery Engine (e.g. resource set) for a set of constraint specifications added to the validation engine.

The validation engine provides capabilities for

  • adding constraint specifications
  • listing the set of constraints
  • registering listeners for notifications on the changes in the constraint set and other events related to the life cycle of the validation engine.

Validation Manager

The validation manager is singleton that serves as a single entry point for using the validation.

that provides capabilities for

  • accessing the constraint specifications registered through extensions (see EMF-IncQuery @Constraint annotation)
  • initializing a new validation engine

Annotation parameters

  • key (list of parameter names as strings): The keys of a constraint represent the parameters that together identify a given violation. Multiple matches of the same constraint pattern with the same parameter values for keys will be considered as a single violation. Non-key parameters can be accessed as tuples by the API.
  • message (format string): The message to display when the constraint violation is found. The message may refer the key variables between $ symbols, or their EMF features, such as in $keyParam1.name$.
  • severity (string): "info", "warning" or "error"
  • targetEditorId (string): An Eclipse editor ID where the validation framework should register itself to the context menu. Use "*" as a wildcard if the constraint should be used always when validation is started.
  • symmetric (possibly multiple list of parameter names as strings): Parameters listed as symmetric are considered to correspond to the same violation for matches where the values are in a different permutation. Symmetric parameters can be either keys or non-keys, mixing is not allowed.

Example annotation:

@Constraint(
  key = {"key1", "sk1", "sk2"},
  severity = "error",
  symmetric = {"sk1", "sk2"},
  symmetric = {"sp1", "sp2"},
  message = "Some message ${key1} and $param$ and ${sp2}"
)
pattern myPattern(key1, sk1, sk2, sp1, sp2, param) {...}

Validation API

Once you specified your constraints with patterns and the @Constraint annotation, you can either use the marker based validation as before, or use the API to process violations yourself:

ResourceSet myModel; // already initialized
Logger myLogger; // Log4J logger, use Logger.getLogger(this.class) if you need one
IConstraintSpecification constraintSpec = new MyPatternNameConstraint0(); // generated for pattern called MyPatternName
 
ValidationEngine validationEngine = new ValidationEngine(notifier, logger);
IConstraint constraint = validationEngine.addConstraintSpecification(constraintSpecification);
validationEngine.initialize();
 
Collection<IViolation> violations = constraint.listViolations();
for(IViolation violation : violations) {
  System.out.println(violation.getMessage());
  Map<String, Object> keyMap = violation.getKeyObjects()
  for(String key : keyMap.keySet()){
    System.out.println("Key " + key + " is " + keyMap.get(key));
  }
}
 
// you can filter violations
Collection<IViolation> filteredViolations = constraint.listViolations(new IViolationFilter(){
  public boolean apply(IViolation violation){
    return violation.getMessage().contains("MyFilterWord");
  }
});
 
// you can add listeners on IConstraint to get notified on violation list changes
constraint.addListener(new ConstraintListener(){
  public void violationAppeared(IViolation violation){
    System.out.println("Appeared: " + violation.getMessage());
  }
  public void violationDisappeared(IViolation violation){
    System.out.println("Disappeared: " + violation.getMessage());
  }
});
 
// or on IViolations to get notified of message and parameter changes
violations.iterator().next().addListener(new ViolationListener(){
  public void violationEntryAppeared(IViolation violation, IEntry entry){
    System.out.println("Entry appeared: " + entry);
  }
 
  public void violationMessageUpdated(IViolation violation){
    System.out.println("Message updated: " + violation.getMessage());
  }
 
  public void violationEntryDisappeared(IViolation violation, IEntry entry){
    System.out.println("Entry disappeared: " + entry);
  }
});
 
// you can also remove constraint specifications from an engine
validationEngine.removeConstraintSpecification(constraintSpecification);
 
// and dispose it when no longer needed
validationEngine.dispose();