8.1.x Tracing and Resolving
Execution of a mapping establishes a trace record
to maintain the relationship between its context object and
the result object or objects. This relationship can be queried
by the execution of another mapping using one of the eight resolve
operations.
8.1.x.1 Trace Records
Execution of a transformation builds the overall trace
data which comprises a sequence of trace record;
one for each mapping execution. This including any mappings
executed by accessed or extended transformations or libraries.
Each trace record comprises:
- context-parameter - the context (or source)
parameter object
- in-parameters - the in (and inout) parameter
objects or values
- invoked-mapping - the invoked mapping operation
- executed-mapping - the executed mapping operation
- out-parameters - the out (and inout) parameter
objects or values
- result-parameters - the result (or target)
parameter object or objects
The invoked-mapping and executed-mapping
operations may differ when a disjuncting mapping is
invoked. The invoked-mapping is the disjuncting
mapping. The executed-mapping is the
successfully selected candidate mapping or null.
inout parameters are traced twice, once as in-parameters
and again as out-parameters.
The trace record is created with context-parameter,
in-parameters, invoked-mapping and executed-mapping
fields at the start of the initialization section of the
selected candidate mapping. This is after predicates
have been executed as guards or pre-conditions. The initially
null value of the out-parameters and result-parameters
fields is updated at the end of the candidate mapping
execution. In the case of a standard mode execution for which
no candidate mapping is selected, the trace record contains null
entries for executed-mapping, out-parameters
and result-parameters fields.
The trace record traces the source/target
relationship; it does not trace object construction or
helpers. If a trace is needed, these untraced facilities must
be wrapped up inside a mapping.
8.1.x.2 resolve() - Resolution of target objects by Type
The trace data may be queried to identify all
target objects using the resolve operation without a
context object or argument.
The query may be restricted to identifying all target objects
conforming to a given type by adding a type argument.
The returned target objects may be further restricted to
those mapped from a particular source object by supplying the
source object as the context object.
Additionally, or alternatively, the returned target objects
may be restricted by an OCL condition.
source.resolve(t : Table | t.name.startsWith('_'));
These queries return a sequence of target objects.
An equivalent OCL-like query for SOURCE.resolve(T : TYPE |
CONDITION) is
let selectedRecords = trace-data->select(in-parameters->including(context-parameter)->includes(SOURCE)) in
let selectedTargets = selectedRecords->collect(out-parameters->union(result-parameters))->flatten() in
selectedTargets->selectByKind(TYPE)->select(T | CONDITION)
8.1.x.3 resolveIn() - Resolution of target objects by
Mapping
The trace data may be queried to identify all
target objects produced by a given invoked disjuncting mapping
or executed candidate mapping using the resolveIn
operation.
The returned target objects may be restricted to those mapped
from a particular source object by supplying the source object
as the context object.
source.resolveIn(Class2Table);
Additionally, or alternatively, the returned target objects
may be restricted by an OCL condition.
source.resolveIn(Class2Table, t : Table | t.name.startsWith('_'));
These queries return a sequence of target objects.
An equivalent OCL-like query for SOURCE.resolveIn(MAPPING, T
: TYPE | CONDITION) is
let selectedRecords1 = trace-data->select(in-parameters->including(context-parameter)->includes(SOURCE)) in
let selectedRecords2 = selectedRecords1->select((invoked-mapping = MAPPING) or (executed-mapping = MAPPING)) in
let selectedTargets = selectedRecords2->collect(out-parameters->union(result-parameters))->flatten() in
selectedTargets->selectByKind(TYPE)->select(T | CONDITION)
8.1.x.4 invresolve() - Resolution of source objects by
Type or Mapping
The corresponding inverse queries identifying source objects
conforming to a given type or mapping is available using the invresolve
or invresolveIn operations.
target.invresolve(t : Table | t.name.startsWith('_'));
target.invresolveIn(Class2Table, t : Table | t.name.startsWith('_'));
8.1.x.5 resolveone() - Resolution of a single source or
target object by Type or Mapping
The four resolveone variants of the four resolve
operations modify the return to suit the common case where
only a single object is expected. The normal return is
therefore the resolved object or null. However if
multiple resolutions are available, the assertion that there
is at most one resolution is not satisfied and execution
fails,.
source.resolveone(t : Table | t.name.startsWith('_'));
source.resolveoneIn(Class2Table, t : Table | t.name.startsWith('_'));
target.invresolveone(t : Table | t.name.startsWith('_'));
target.invresolveoneIn(Class2Table, t : Table | t.name.startsWith('_'));
8.1.x.6 Late resolution
The resolve operations query the prevailing state
of the trace data. resolve cannot
therefore return results from mappings that have yet to
execute. This may require careful sequencing of mapping
execution. Alternatively a late keyword may prefix
the resolve when the resolve occurs within an
assignment. This defers the execution of the assignment and
the partial computation involving late resolve's
until all mapping executions have completed. More precisely,
mappings execute, assignment right hand sides involving late
resolutions are computed, then finally deferred assignments
are made. The ordering in which late resolutions occur does
not matter, since each late resolution can influence only its
own deferred assignment.
myprop := mylist->late resolve(Table);
This last example also demonstrates that an implicit
imperative xcollect of resolutions may be performed, in this
case requiring the collection to be performed after all
mappings have executed.
8.1.x.7 Redundant execution
The trace data is used to suppress re-execution of
any previously executed mapping in favor of the previous
execution.
A candidate mapping execution is suppressed to
avoid creating a trace record whose context-parameter,
in-parameters, invoked-mapping and executed-mapping
fields duplicate another trace record is already in
the trace data. When comparing trace record
fields, Class instances are compared as objects without regard
for their content, and DataType values are compared by deep
value equality. Traced object instances may therefore be
modified between mapping executions without inhibiting
detection of re-execution since only the object references are
traced. However any modification of a traced DataType value
such as a List inhibits detection of a re-execution since the
entire value is traced.
When a re-execution attempt is detected, the re-execution is
suppressed without any additional trace record being
created. The out-parameters and result-parameters
fields of the previous execution are re-used as the
corresponding returns of the re-execution attempt.
8.1.x.8 Persisted Trace Data
The trace data may be persisted and reloaded to
support a re-execution. However since the trace record
does not trace multiple object states, configuration data,
transformation context or intermediate data, it is not
possible to use a persisted form of the trace data
to support incremental re-execution of an arbitrary QVTo
transformation. A well-behaved transformation that avoids
mutating objects or other untraced facilities may be
re-executable.