This scenario uses unfinished/experimental named object links feature - it is very powerful but even more experimental than linked objects feature as a whole! So beware, everything described here can change any time.
Let us have a set of devices that have the following characteristics:
- A device is used by no one or a single user at any given time.
The device gives its user some properties, namely user's
organizationobtains value of "D users" for any owned device D.
On the other hand, the device knows who uses it by storing the owner
We want to make sure characteristics 2 and 3 hold also when ownership of the device changes and/or when relevant properties (owner
fullName and device
An implementation overview
The implementation has two parts:
- Implementing the data transfers as such. This means that when we are processing a user (owner) we want to set correct
organizationvalue(s) on him. And vice versa, when we are processing owned device, we want to set correct
descriptionbased on owner's data.
- Triggering the recomputation of linked objects. So if we are changing a user, we need to recompute affected owned devices, if there are any. And if we are changing an owned device, we need to recompute affected owner, if there is any.
Data transfer is done using mappings: either induced from archetypes or present in object templates.
For triggering the recomputation of linked objects we currently have only one convenient way: policy rules. (A direct alternative is using scripting hooks but it's a lot more work. Also some global recomputation of changed objects could be devised but would be quite awkward as well.)
Data transfer implementation using mappings
organization property is computed using mapping induced by archetype:
The code calls
midpoint.findLinkedTargets method to look for all linked objects for
devices link type. Wait... what's link type?
It seems that it is beneficial to categorize object links into so called link types. In our scenario, all links between a user and his/her device(s) are of "user-devices" link type. When viewed from the user point of view, this link type is simply called "devices".
It is defined in the same
gummi-user archetype and it looks like this:
The definition states that all objects of type
ServiceType and archetype
device, linked to users with archetype
gummi-user are considered to be
devices and can be referenced under this name.
When returning to our mapping, the code
finds all devices (meant by the definition above) linked to the current object, collects their names and creates a set of values in the form of "D1 users", "D2 users", ..., "Dn users" - for devices D1, D2, ..., Dn.
These value are then put into multivalued
organization property. Note that the target range is set to
all meaning that any other values will be removed.
What is important here is that if you used this mapping not in assignments but in object template, you would need to set
afterAssignments. It is because
findLinkedTargets method acts on the new state of assignments, looking at
roleMembershipRef values that are going to be set - not at values that were present in the object when the computation started.
midpoint.findLinkedTargets method has relativistic behavior: it returns data derived from the new state of focal object if evaluating "new" state and the data derived from old
roleMembershipRef values if evaluating the "old" state.
(But because we use it in assigned focus mapping, it is evaluated in the correct place.)
device archetype looks like this:
Here we see the definition of "user-devices" link from the other side: a device can have a link whose source (i.e. assignment holder) is of
UserType type. One could add also archetype reference to
gummi-user but it's not strictly necessary, because these devices will not be owned by any other users.
midpoint.findLinkedSource('user') then finds the linked user (if any). And the mapping returns the value for the
description property accordingly.
Triggering the recomputation
We need to trigger recomputation both ways:
- If something relevant changes on the device object, the owning user must be recomputed.
- If something relevant changes on the user object, the owned devices must be recomputed.
Recomputing device when the user changes
There are the following situations when the device should be recomputed:
|1||Owner ||This is the simplest case.|
|2||The link itself is changed||We consider link to be changed if the |
|3||User is added (including the link)||This is a special case of the above - a specific value of |
|4||User is deleted (had the link before)||This is (again) a special case of the above - a specific value of |
These can be implemented by the following policy rules (induced by
The first policy rule invokes recomputation on all linked devices if user's name or full name changes. This covers situation #1.
The second policy invokes recomputation on all linked devices whose membership has changed (see changeSituation = changed setting). This covers situation #2, but also situations #3 and #4.
(Temporary) workaround for situation #4: However, because assignment evaluator skips evaluating assignments when object is deleted, the respective policy rule must be presented to the object in some other way.
So this global policy rule has to be used:
Recomputing user when device changes
Recomputation of user on device change is ensured using the following policy rule in the
The code is almost self-describing. When device name changes, all linked users (zero or one) are recomputed.
What is missing here is treatment of the situation when the device is abruptly deleted without being unassigned first.
This section needs to be expanded. However, documentation work is similar to the development work in that it takes time and that it needs funding.
If you are midPoint subscriber, you can request that we complete this section and we will do that as soon as possible.
Only some wild thoughts here: If the device is deleted, its owner should be recomputed. But perhaps not only recomputed: the assignment to (now) non-existing device should be removed as well. However, this is tricky. Do we really want this?
- Yes: on device deletion we want to remove the assignment from its owner; causing the complete recomputation.
- Partially: on device deletion we want to keep the assignment but we want to recompute the owner.
- No: on device deletion we don't want to do anything. I.e. we want the devices to be deleted gracefully: first, their owner should be explicitly removed and only after that they should be deleted.
- We might want to automate this process. We'll put the device into
retiredlifecycle state. And then there will be a task that will look for such devices, unassigning them from their owner(s) and eventually deleting them.
- We might want to automate this process. We'll put the device into
- Really not: we do not want to allow regular device deletion if it has an owner.
Complete configuration for this scenario is in https://github.com/Evolveum/midpoint/tree/master/model/model-intest/src/test/resources/linked/gummi directory (and system configuration in the parent one).