MidPoint mappings are designed to work correctly with the relative change model that is a fundamental principle of midPoint operation. Simply speaking the mapping does not just maps the source values to the target values. It also maps the corresponding deltas.
TODO: better explanation:
- Picture how a delta is translated through mapping
- correct support for multi-value properties
Scripting Expressions in Mappings
Most expression types used in mappings are built to work with deltas
path expressions) and they do it correctly and efficiently. However scripting expressions are different. Scripting languages are not designed to work with deltas. The variables and return values of scripting languages are simple static values. Therefore we need a little trick to make them work correctly with deltas without sacrificing the simplicity and convenience of traditional scripting approach: Scripting expression is usually evaluated individually for every applicable value. The applicable value is either old or new value of the property or value added or removed by the delta. The mapping knows which expression input values were added, removed or stay unchanged and therefore it can assume the same also for expression output values and construct the resulting delta. In other words the delta is first decomposed into individual values, then an expression is evaluated for each of these values and then resulting values are composed back to a delta.
This approach may be quite simple for a single changed property. But it gets considerably complicated when multiple changes occur at the same time. In such a case the input deltas needs to be decomposed into combinations of values from all the deltas and then composed back. MidPoint mappings fully support this mechanism also for multi-value properties.
Script Expression Sources
For the scripting expression to work correctly the mapping must be able to identify what was changed and which part of the change is important for the script. E.g. it is not sufficient to know that user properties
employeeType changed (as represented in object delta). The mapping must know that only the
fullName property is important for the script. Otherwise the mapping would need to combine all the changes from all the applicable deltas and execute the script for all the applicable combinations. The number of possible combinations can be significantly large if multiple multi-value properties change. As the script in this case only cares about the value of
fullName attribute then most of such executions will be pointless anyway and the results would be discarded. Which is obviously a waste of resources. But the mapping does not know which script executions to discard until it has the return value - unless there is way to specify that only the
fullName property is interesting for the script. There is no generic implicit way how to do it with a scripting language code that will work sufficiently well for all supported scripting languages. Therefore an explicit method is needed: mapping
source definition tells the mapping that only a specific properties are interesting for the mapping. Therefore the script evaluation code in the mapping knows how to efficiently construct input values for the script, when to evaluate it and, most importantly, when there is no need to evaluate it. Therefore correct specification of
source in a mapping that contains a scripting expression is critical for correct evaluation of such expression. If a
source declaration is missing then a script may not be invoked at all and will not pass a value to the output. If too many
source declarations are present for a script then the script may be invoked too often which might result in waste of system resources.
TODO: better explanation:
- Picture how a delta is translated through SCRIPTING mapping
- relative and absolute mode
Mappings usually work only with values that are non-null. The mapping simply ignores all properties and deltas without a value. Therefore a script will usually not be executed with all its input values set to
null. However there are two cases when mapping needs to deal with empty values:
- when a change causes empty property to become non-empty,
- when a change causes non-empty values to become empty.
E.g. these cases needs to be handled for scripts that supply a default values for empty properties. In this case the script must be executed with a
null input parameter otherwise the script would not have any chance to produce a value. Similar reasoning also applies to mapping conditions that checks for "negative" cases, e.g. a condition that will assign a default role if no other role is assigned to a user.
Therefore a script needs to check for
null input values to be able to correctly respond to all situations. However this may make scripting code ugly and complex, littered with checks for null inputs. Therefore there is a way how to avoid invoking script with
Please note that this setting will skip execution of a script if all inputs are null. This means that the script will be executed with non-null values only if there is a single mapping source. If there are several mapping sources then the script still may be executed with
null inputs, e.g. in case that one source is
null while the others are non-null. In such a case this setting will make the script execution more efficient (skipping some executions) however proper checking for null values is still needed.
There is also a convenient script function
basic.isEmpty() that can provide null-safe check for empty value:
While midPoint is built with Relativity in mind, this relativity is not complete. MidPoint evolution, and especially financial and scheduling constraints, forced us to make compromises during midPoint development. This does not affect correctness of midPoint computation, but it may affect performance. The deployments that rely on a lightweight processing of large number of small changes may be affected. Please see Complete Relativity page for more details.