Linked Objects

Last modified 18 Sep 2025 13:05 +02:00
Linked objects feature
This page describes configuration of Linked objects midPoint feature. Please see the feature page for more details.
Since 4.2
This functionality is available since version 4.2.

Introduction

MidPoint objects do not live in isolation. Often they need to take data from related objects. And so if an object changes, the change needs to be cascaded to related objects.

This page introduces the topic theoretically. For code samples, see:

There are many kinds of links among objects. They are differentiated by the relation attribute of a particular object reference. (For more information on relations, see Relation and Relation Configuration.)

These are typical situations when two objects are linked:

Table 1. Situations when objects are linked
Situation Link source Link target Relation Note

User A has a role R.

User A

Role R

org:default

User A is a member of org O.

User A

Org O

org:default

User A is a manager of org O.

User A

Org O

org:manager

User A is an owner of token T.

User A

Service T (archetyped as token)

org:default

(Or org:owner.)

User A is a child of user B.

User A

User B

custom:child

Currently unsupported. The only user-user assignments we support are delegation assignments.

Role R has a metarole M.

Role R

Role M

org:default

(Or org:meta.)

User A is an approver for role R.

User A

Role R

org:approver

A link between two objects can be:

Table 2. Links between objects
Type of link Stored in Note

prescribed

assignment

actual

roleMembershipRef

Besides roles, roleMembershipRef can also contain any object that can be assigned, such as archetypes, or organizations. When (un)assigning archetypes, archetypeRef is also created in addition to roleMembershipRef. Similarly, parentOrgRef is created when (un)assigning between two organizations.

So the link between two objects (A → B) can be in one of the following states:

Table 3. Object link states
Prescribed Actual Description

Yes

Yes

The usual case. There is an assignment from A to B. The assignment is valid and effective, so the information is in roleMembershipRef as well.

Yes

No

There is an assignment from A to B. But it is either invalid (from the activation point of view) or not effective (from the conditions point of view), so there is no record in roleMembershipRef.

No

Yes

There is no direct assignment from A to B, but the link was created indirectly, e.g., via an inducement, such as from A to B, where B induces C. So A → C is not prescribed but actual.

No

No

A and B have no link altogether, or there is an indirect assignment that is not valid or not effective.

Each link has two participants:

Table 4. Link participants
Participant Meaning

Link source

Object that has something linked. Usually it is the holder (owner) of the respective assignment.

Link target

Something that is linked to the object.

In mappings we can use the following methods to find the other side of our links:

Table 5. Methods for determining link source and target
Method To be invoked on Meaning Search criteria Version returning single object

midpoint.findLinkedTargets

link source

Returns all linked objects matching specified criteria.

object type, archetype (experimental: link type name)

findLinkedTarget

midpoint.findLinkedSources

link target

Returns all objects that have the current one as link target.

object type (experimental: link type name)

findLinkedSource

Note that findLinkedTargets should be used only after assignments are processed as it needs fresh information from assignment evaluation. Therefore:

  • You cannot use findLinkedTargets in inbound mappings.

  • If you use findLinkedTargets in object templates, you need to specify the evaluationPhase of afterAssignments.

  • You can use findLinkedTargets in assigned/induced focus mappings or resource outbound mappings.

On the other hand, findLinkedSources has no such limitation. For examples, see individual scenarios for linked objects.

The midpoint.findLinkedTargets method has relativistic behavior: it returns data derived from the new state of a focal object if evaluating the new state, and the data derived from old roleMembershipRef values if evaluating the old state.

On the other hand, midpoint.findLinkedSources returns the same data in both the old and new stats, because the links from sources to the focal object are not changed in the course of the focal object processing.

Cascading the changes

We often need to recompute one side of the link when relevant parts of an object on the other side (or the link itself) change. We usually use a policy rule with a scriptExecution policy action for this.

Selecting objects to be recomputed

The scriptExecution policy action has an option to specify objects to which the given midPoint script (action) should be applied. This option is called object and has the following values:

Table 6. scriptExecution policy options
Option Cardinality Action is run on Option value type Note

currentObject

single

The current focus object. This is the default if nothing is specified.

ObjectSelectorType

linkTarget

multiple

Objects that are targets of links coming from this object (i.e. results of assignments of this objects) are recomputed.

LinkTargetObjectSelectorType

linkSource

multiple

Objects that are sources of links coming to this objects (i.e. objects that have assignments to this object) are recomputed.

LinkSourceObjectSelectorType

namedLinkTarget

multiple

A shortcut for linkTarget with a specified linkType.

string

Experimental. May be removed.

namedLinkSource

multiple

A shortcut for linkSource with a specified linkType.

string

Experimental. May be removed.

Object sets coming from individual options and also from individual values of these options are added together.

The values of the above options are used to select what specific link targets or sources to use; and under what conditions the current object is to be selected. You can use these filters (and-ed together when present in a single value):

Table 7. Filters for specifying link targets and sources
Filter Meaning ObjectSelectorType LinkTargetObjectSelectorType LinkSourceObjectSelectorType

type

Type of the object.

yes

yes

yes

subtype

Subtype of the object.

yes

yes

yes

archetypeRef

Archetype of the object.

yes

yes

yes

orgRef

Top node of an organizational hierarchy. This node and all of its subnodes (transitively, unlimited depth) are considered matching.

yes

yes

yes

filter

Filter that an object must match to be considered selected. This filter MUST NOT contain organization unit clauses. It may only contain property clauses, logical operations and so on.

yes

yes

yes

relation

Link matches if it has any of the relations specified. (If no relation is specified, all relations match.)

yes

yes

linkType

Name of the declared link type. (Experimental)

yes

yes

changeSituation

Filters objects to which policy actions apply based on how links to those objects have changed. See the available values.

yes

matchesRuleAssignment

The link target is related to the assignment that brought this policy rule to the focus object. This setting can eliminate the need to specify linked targets, e.g., via archetype, if the archetype itself brings this policy rule to the object.
This filter is not precise as it ignores relations, and also whether the assignment that brought this policy rule was really the one that is listed in (old/new) roleMembershipRef. Do not use this if you need absolute precision.

yes

matchesConstraint

The link target was matched by a policy constraint in this rule (e.g., an assignment modification constraint has a target object equal to the assignment target). This setting can eliminate the need to specify linked targets, e.g., by using archetypes.
Highly experimental, probably will be removed.

yes

Possible values of the changeSituation filter are:

Table 8. changeSituation values
Value Meaning Old existence New existence

always

Always matches (default), even if the link was removed.

any (X)

any (Y)

added

Matches only if the link has been added.

false

true

removed

Matches only if the link has been removed.

true

false

inNew

Matches if the link exists in the new state.

any (X)

true

inOld

Matches if the link exists in the old state.

true

any (X)

changed

Matches if the state of the link’s existence has changed, i.e., if it has been added or removed.

any (X)

not X

unchanged

Matches if the state of the link’s existence has not changed.

any (X)

X

Example of recomputing devices when user name changes
<policyRule>
    <policyConstraints>
        <or>
            <modification>
                <item>name</item>
            </modification>
            <modification>
                <item>fullName</item>
            </modification>
        </or>
    </policyConstraints>
    <policyActions>
        <scriptExecution>
            <object>
               <linkTarget>
                   <archetypeRef oid="........"/>
               </linkTarget>
            </object>
            <executeScript>
                <s:recompute/>
            </executeScript>
        </scriptExecution>
    </policyActions>
</policyRule>

This rule triggers a recomputation of all linked objects with specified archetype when the name or fullName of the current object is modified. For more information on object recomputation, see recompute.

Asynchronous execution

In situations where there are many objects to be recomputed, you can specify asynchronous execution, i.e., execution of the recomputation in the context of a background task.

This is done using the asynchronousExecution item containing the following options:

Table 9. asynchronousExecution options
Option Meaning Example

executionMode

Mode of asynchronous script execution.

iterative (the default)

taskTemplateRef

Reference to the task template, i.e., the task that is used as a template (prototype) of the actual task being created.

taskCustomizer

An expression that takes a task and customizes its content.
Input variable:preparedTask (of TaskType).
Output: object of TaskType type that should be used.
The script can simply modify preparedTask and return it, see an example. Note that this is the final step in task preparation, and so the task is executed in the form that is prepared by this expression.

Asynchronous execution modes

The following modes are available:

Table 10. Asynchronous execution modes
Execution mode Meaning Note

iterative

Uses an iterative scripting handler, i.e., an object query with a script that processes every object found.

This is the default and recommended option.

singleRun

Uses a single-run scripting action. Input for this action contains references to objects that should serve as action inputs.

To be used only in complex and advanced cases. When in doubt, use iterative.

singleRunNoInput

Uses single-run scripting action without any explicit input.

Task templates

The task template can contain any options you want to be present in the final task. Its state should be waiting or closed to avoid being run independently. The following items are set for the final task (so overwriting the items present in the template):

Table 11. Task template parameters
Item Meaning Value set

name

Task name

Name of the task template (or Execute script if no template is specified) plus a random number suffix.

ownerRef

Task owner

Currently logged-in user, or the user specified in runAsRef for script execution policy action.

executionStatus

Task execution status

RUNNABLE (The task should be run.)

archetype assignment

Task archetype

00000000-0000-0000-0000-000000000509 (Iterative bulk action task) for iterative execution mode and 00000000-0000-0000-0000-000000000508 (Single bulk action task) for other execution modes.

taskTemplateRef can contain an object filter, even with expressions. Those expressions can refer to the focus, policyAction, policyRule and configuration. variables.

Example of taskTemplateRef
<asynchronousExecution>
    <executionMode>iterative</executionMode>
    <taskTemplateRef>
        <filter>
            <q:text>
                . inOid ```
                            import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType
                            focus instanceof OrgType ? '9c50ac7e-73c0-45cf-85e7-9a94959242f9' : '9107b8a4-0a0a-4e82-a4c6-9d84034f9d6e'
                        ```
            </q:text>
        </filter>
    </taskTemplateRef>
    ...
</asynchronousExecution>

Task customizer

You can specify any other task properties (or delete any pre-set ones) using a special expression that expects preparedTask as its input and should return a modified task object. The returned object can be the one that was received as input (with necessary modifications).

Example taskCustomizer
<asynchronousExecution>
    <taskCustomizer>
        <script>
            <!-- This script assumes the existence of the `memberRecomputationWorkerThreads` integer property in the `ModelExecutionOptionsType` extension.
                 It uses the value of this option to set worker threads (mext:workerThreads task property) for given task. -->
            <code>
                log.info('Task being prepared = {}', preparedTask.asPrismObject().debugDump())
                preparedTask.description = 'Hello there'
                workerThreads = midpoint.getExtensionOptionRealValue('memberRecomputationWorkerThreads')
                basic.setTaskWorkerThreads(preparedTask, workerThreads)
                preparedTask
            </code>
        </script>
    </taskCustomizer>
</asynchronousExecution>

Delaying recomputation using triggers

There are situations when you want to delay the recomputation. A typical case is when you want to recompute members of abstract roles that are (potentially) changed on a larger scale. For example, when they are synchronized from a resource. Or if they are modified using an action. Or if it is simply expected that users are going to edit more roles via GUI in a short period of time (relative to the time needed to recompute members of those roles).

In such cases you can set a recompute trigger on the relevant objects instead of recomputing them immediately. The trigger can be set either unconditionally, or for a given time in the future. The latter option optimizes even the creation of the triggers by skipping triggers that are known to be redundant. See recompute for more details.

Note: Triggers can be set synchronously or asynchronously. The asynchronous option is suitable for roles with lots of members.

Enabling/disabling the change propagation

To enable/disable change propagation directly when submitting operations, e.g., via GUI, midPoint uses the concept of ModelExecuteOptions extension items. You can define these using the standard extension mechanism, for example:

Extension mechanism example
<xsd:schema elementFormDefault="qualified"
            targetNamespace="http://midpoint.evolveum.com/xml/ns/samples/linked"
            xmlns:tns="http://midpoint.evolveum.com/xml/ns/samples/linked"
            xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
            xmlns:a="http://prism.evolveum.com/xml/ns/public/annotation-3"
            xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <xsd:complexType name="ModelExecutionOptionsTypeExtensionType">
        <xsd:annotation>
            <xsd:appinfo>
                <a:extension ref="c:ModelExecuteOptionsType"/>
            </xsd:appinfo>
        </xsd:annotation>
        <xsd:sequence>
            <xsd:element ref="tns:recomputeMembers" minOccurs="0"/>
        </xsd:sequence>
    </xsd:complexType>

    <xsd:element name="recomputeMembers" type="xsd:boolean">
        <xsd:annotation>
            <xsd:documentation>
                Enables or disables recomputation of members - for abstract roles or their archetypes
                that look at this extension property.
            </xsd:documentation>
        </xsd:annotation>
    </xsd:element>
</xsd:schema>

And then you could check for this option in conditions related to the particular policy rules, for example:

<inducement>
    <policyRule>
        <documentation>
            When department cost center changes, members must be recomputed
            (unless explicitly disabled in execution options).
        </documentation>
        <policyConstraints>
            <modification>
                <item>costCenter</item>
            </modification>
        </policyConstraints>
        <policyActions>
            <scriptExecution>
                <object>
                    <linkSource/>
                </object>
                <executeScript>
                    <s:recompute/>
                </executeScript>
                <asynchronousExecution/>
            </scriptExecution>
        </policyActions>
    </policyRule>
    <condition>
        <expression>
            <script>
                <code>midpoint.extensionOptionIsNotFalse('recomputeMembers')</code>
            </script>
        </expression>
    </condition>
</inducement>

The specific options cannot be (now) set via GUI. However, they can be specified in actions, synchronization reactions, or anywhere where the model API is called from a Java or Groovy code. In the future we will also implement support for REST calls.

TODO

Authorizations should be checked when processing execution options. Currently they are not.

Example of setting the options within a synchronization reaction:
<reaction>
    <situation>linked</situation>
    <synchronize>true</synchronize>
    <executeOptions>
        <extension>
            <linked:recomputeMembers>false</linked:recomputeMembers>
        </extension>
    </executeOptions>
</reaction>

Security aspects

  • The midpoint.findLinkedSources and findLinkedTargets methods use the model API to retrieve objects, so they are executed under privileges of the currently logged-in user. You can use the runAsRef mechanism in expressions to define a different user, if needed.

  • Scripts (actions) in scripting policy rules also execute under privileges of the currently logged-in user. You can use scriptExecution.runAsRef to define a different user.
    There is one exception, though: to increase performance, the search for relevant objects (linked sources or targets) is done directly via the repository. So the security is not being applied there. This might change in the future.

Performance considerations

There are many topics related to performance to consider, including the following:

  • Should change propagation be processed in the foreground or background?
    If there are only a few linked objects, and if their recomputation is fast, it can be done on the foreground. If you only want to trigger the recomputation via triggers, it can be also done in the foreground (even for a slightly larger sets of linked objects). But for all other cases, background processing is preferred. And, if processing more focus objects with potentially overlapping sets of linked objects, using triggers is strongly advised to avoid repeated recomputation.

  • Where should you use change propagation policy rules?
    For example, in the user device scenario (Linked objects scenario 2: Devices owned by users), policy rule that causes the recomputation of linked devices can be put either into the user archetype (with order 1 inducement) or the device archetype (with order 2 inducement).
    The advantage of the latter case is that it is applied to the user only if the user has at least one device (so sparing some processing time.) The disadvantage is that if a user has multiple devices, the policy rule is present multiple times: once for each device. And here comes the distinction: if the rule recomputes all devices, this would lead to their repeated recomputation. So, if you have a rule that recomputes all linked objects of a kind, then it should be induced only once, i.e. assigned to the user from the user archetype. If the rule recomputes only relevant devices (using the matchesRuleAssignment or matchesConstraint clause) or it is expected that there is at most one matching linked object, it can be attached to target’s archetype.

  • Looking for sources and targets in the midpoint.findLinkedSource and midpoint.findLinkedSource methods.
    The former uses a traditional repository query, as it has no hints of who the sources could be. It can be fast or slow, depending on the complexity of the query and the number of objects returned. Fortunately, the result should be cached (locally or globally), so the repo cost will be incurred only once. When looking for targets, the candidate set of objects is taken from assignments and preliminarily filtered on object type. However, further filtering requires fetching these objects by their OID. In extreme cases, that might present hundreds of objects. The repo calls should be cached. However, in both cases, the objects pass the model getObject/searchObjects methods, so all the model processing (security, template, post read hooks) is applied. And as it is not treated by cache, it is applied each time those methods are used. If this is an issue, you need to write your own (optimized) versions of these methods or, providing that a platform subscription is in place, request such changes from Evolveum.

Compliance

This feature is related to the following compliance frameworks:

Was this page helpful?
YES NO
Thanks for your feedback