<correlation>
<q:equal>
<q:path>employeeNumber</q:path>
<expression>
<path>$account/attributes/ri:hrId</path>
</expression>
</q:equal>
</correlation>
Correlation-Time Mappings
Since 4.5
This functionality is available since version 4.5.
|
Before 4.5
Before 4.5, the correlation expressions used to look like this:
This expression means that we want to correlate hrId
attribute of an account to the employeeNumber
property
of an existing user, i.e. we are looking for a user with employeeNumber
property being equal to hrId
property
of the shadow being correlated.
Usually, such correlation rule is accompanied by an inbound mapping that transfers the value of hrId
attribute
to user employeeNumber
property, after the correlation is done (either providing the value for a new user, or updating
the value for existing one). Like this:
employeeNumber
from the value of hrId
<attribute>
<ref>ri:hrId</ref>
<displayName>HR Identifier</displayName>
<inbound>
<strength>strong</strength>
<target>
<path>employeeNumber</path>
</target>
</inbound>
</attribute>
The problem with this approach is that the information about the relation between hrId
and employeeNumber
has to be maintained at two distinct places. They are usually not even physically close to each other.
And the situation starts to be much worse if there are non-trivial transformations to be done there. For example,
let us assume that the employeeNumber
should contain the string after 3rd character if HR ID starts with A
,
and the string after 5th one, otherwise. The mapping would be:
employeeNumber
from the value of hrId
(with more complex computation)<attribute>
<ref>ri:hrId</ref>
<displayName>HR Identifier</displayName>
<inbound>
<strength>strong</strength>
<expression>
<script>
<code>
input.startsWith('A') ? input.substring(3) : input.substring(5)
</code>
</script>
</expression>
<target>
<path>employeeNumber</path>
</target>
</inbound>
</attribute>
And the correlation expression:
hrId
and employeeNumber
<correlation>
<q:equal>
<q:path>employeeNumber</q:path>
<expression>
<script>
<code>
hrId = basic.getAttributeValue(account, 'hrId')
hrId.startsWith('A') ? hrId.substring(3) : hrId.substring(5)
</code>
</script>
</expression>
</q:equal>
</correlation>
This is obviously not very maintainable in the long run: When the code for deriving the employeeNumber
from hrId
changes, both places have to be updated. Otherwise, the correlation will not work correctly.
New Options
Starting with midPoint 4.5 it is possible to eliminate this duplication. The same inbound mapping can be used to prepare data for correlation as well as to provide data to be put into the user object.
Using our previous example, we are now able to write the correlation rule like this:
employeeNumber
computed by a mapping<correlation>
<q:equal>
<q:path>employeeNumber</q:path>
<expression>
<path>$focus/employeeNumber</path> (1)
</expression>
</q:equal>
</correlation>
1 | $focus refers to the object computed by inbound mappings. |
The $focus/employeeNumber
is the employee number that was mapped by the inbound mapping from the hrId
attribute.
So, the knowledge that hrId
maps to employeeNumber
(and how exactly) has to be now present at a single place only: in the mapping.
By default, inbound mappings are not evaluated for correlation (yet). [1] Therefore, one has to explicitly enable this. It can be done for all the mappings in given object type:
<schemaHandling>
<!-- ... -->
<objectType>
<!-- ... -->
<mappingsEvaluation>
<inbound>
<defaultEvaluationPhases>
<phase>beforeCorrelation</phase>
<phase>clockwork</phase>
</defaultEvaluationPhases>
</inbound>
</mappingsEvaluation>
</objectType>
</schemaHandling>
The defaultEvaluationPhases
setting specifies that - by default - all inbound mappings for this object type
are evaluated both before correlation (if correlation is needed), and during standard processing (in so-called clockwork).
If not specified, the default setting is clockwork-only execution, i.e. the same behavior as in midPoint 4.4 and earlier.
The phases can be specified also at the level of individual mapping, e.g. like this:
<attribute>
<ref>ri:hrId</ref>
<displayName>HR Identifier</displayName>
<inbound>
<strength>strong</strength>
<expression>
<script>
<code>
input.startsWith('A') ? input.substring(3) : input.substring(5)
</code>
</script>
</expression>
<target>
<path>employeeNumber</path>
</target>
<evaluationPhases>
<include>beforeCorrelation</include>
</evaluationPhases>
</inbound>
</attribute>
You can specify both include
and exclude
keywords here. The former adds a phase or phases to the default list of phases,
whereas the latter removes the specified phase or phases from the default list of phases.
During execution, the mapping is currently executed twice, i.e. results of the execution before correlation are not re-used during clockwork execution. (The execution environments can differ in subtle ways.) This may change in the future. |
As an experimental feature (4.5), the following simplified syntax of correlation expression can be used as well: Listing 8. Correlating on
employeeNumber (experimental feature)
This is equivalent to the condition Please see Smart Correlation for details on how to configure the correlation. The format was slightly changed between the experimental form of this feature in 4.5 and the "production-ready" form in 4.6. |