# Evaluating Constraints and Queries

In the previous topic, we saw how to use the OCLHelper API for parsing OCL constraints and query expressions. Parsing constraints is very interesting in itself, but we can also make OCL come alive in our applications by evaluating these constraints. For this, OCL provides a Query API.

## The OCL Query

Like the OCLHelper for parsing constraints, the OCL facade object provides Query objects for evaluating constraints and query expressions.

> [as SVG]

The Query encapsulates an EvaluationEnvironment providing the run-time values of context variables to the OCL interpreter. These context variables are set and retrieved using the following methods:

- add(String, Object): adds a name-value binding for a variable
- replace(String, Object): replaces an existing variable binding
- remove(): removes a variable binding
- getValueOf(String): obtains a variable value

The context variables of primary interest are self and, in operation constraints, the variables corresponding to its parameters. The EvaluationEnvironment API is also used to supply values for "global" variables added to the parsing Environment by the client.

Another important consideration in the evaluation environment is the allInstance() operation, which obtains the entire extent of a classifier. For data types, this is a simple problem: the extent of an Enumeration is well defined and the extents of other kinds of DataTypes are undefined. For Class extents, the EvaluationEnvironment provides support for an extent map, mapping classes to the sets of their instances, as determined by the client. A client sets the extent map using the OCL.setExtentMap() method. The default extent map, if none is provided by the client, lazily computes the extent of a class from the EMF Resource containing the context element of the evaluation.

So, after optionally setting values of context variables (other than self; the Query takes care of this) and an extent map, simply construct a query and use it to evaluate the expression or check the constraint:

    OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl;
    ocl = OCL.newInstance(EcoreEnvironmentFactory.INSTANCE);
    OCLHelper<EClassifier, ?, ?, Constraint> helper = ocl.createOCLHelper();

    helper.setContext(EXTLibraryPackage.Literals.LIBRARY);
    Constraint invariant = helper.createInvariant(
        "books->forAll(b1, b2 | b1 <> b2 implies b1.title <> b2.title)");
    OCLExpression<EClassifier> query = helper.createQuery(
        "books->collect(b : Book | b.category)->asSet()");

    // create a Query to evaluate our query expression
    Query<EClassifier, EClass, EObject> queryEval = ocl.createQuery(query);

    // create another to check our constraint
    Query<EClassifier, EClass, EObject> constraintEval = ocl.createQuery(constraint);

    List<Library> libraries = getLibraries();  // hypothetical source of libraries

    // only print the set of book categories for valid libraries
    for (Library next : libraries) {
        if (constraintEval.check(next)) {
            // the OCL result type of our query expression is Set(BookCategory)
            @SuppressWarnings("unchecked")
            Set<BookCategory> categories = (Set<BookCategory>) queryEval.evaluate(next);

            System.out.printf("%s: %s%n", next.getName(), categories);
        }
    }

One of the advantages of the Query API is that a query's evaluation environment can be reused for multiple evaluations, as above. The extent of any classifier is only computed once. For convenience, however, in situations where only a single evaluation is required, the OCL class provides shortcuts:

    // check a single library
    Library lib = getLibrary();  // hypothetical source of a library

    // check whether it satisfies the constraint
    System.out.printf("%s valid: %b", lib.getName(), ocl.check(lib, constraint)) {

The Query API also provides methods that work on multiple elements. The first example, above, could be written more succinctly as:

    List<Library> libraries = getLibraries();  // hypothetical source of libraries

    // only print the set of book categories for valid libraries
    for (Library next : constraintEval.select(libraries)) {
        @SuppressWarnings("unchecked")
        Set<BookCategory> categories = (Set<BookCategory>) queryEval.evaluate(next);

        System.out.printf("%s: %s%n", next.getName(), categories);
    }

Copyright (c) 2000, 2007 IBM Corporation and others. All Rights Reserved.