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);
for
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.