Prism 5 Design

Last modified 25 Oct 2021 16:22 +02:00

Design notes for Prism 5 (Prism included in MidPoint 5).

Empty, NonExistent and Null

No Item and No Values

Item may not exist at all:

<user>
    <!-- no assignment here -->
</user>
  1. in JSON …​

{
    "@root" : "user"
}
  1. which would be the same as empty list:

{
    "@root" : "user",
    "assignment" : [ ]
}

The right way how to express this in Prism is not to include the item in prism structures:

PrismObject(user)
    PrismObjectValue
        // no PrismContainer here

However, this may be complicated by metadata or incompleteness. E.g. the "we are sure that Jack has no criminal records":

{
    "@root" : "user",
    "name" : "jack",
    "criminalRecord" : {
        "@value" : [ ],
        "@metadata" : {
            "loa" : "high"
        }
    }
}

In that case there will be an item (container) in Prism, but it will have no value:

PrismObject(user)
    PrismObjectValue
        PrismContainer(criminalRecord) + metadata
            // no PrismContainerValue here

The "no item" case and the "item with no values" case are logically equivalent. They should result in the same behavior.

The canonical way is the "no item" case, e.g.:

{
    "@root" : "user"
}

Prism should avoid creating empty items unless there is a very good reason to do so (e.g. item metadata).

Empty Value

We need to have "empty elements", such as <mapping/> or <asIs/>. We thought about the world where we would not need such elements, but there seem to be no elegant way how to express "mapping with all default values".

Let’s have a case of empty assignment:

<user>
    <assignment/>
</user>
{
    "@root" : "user",
    "assignment" : [ {} ]
}

This will be reflected in Prism as an item with empty value:

PrismObject(user)
    PrismObjectValue
        PrismContainer(assignment)
            PrismContainerValue
                (no items here)

Item with empty value is different than non-existent item (no item at all). E.g. no mapping item means that there is no mapping, the value should not be mapped from user to account. Empty mapping means that there is a mapping, the values should be mapped from user to account, using the default setting.

This makes a difference in the query language as well. The "no item" case will match NOT EXISTS filters. The "empty item" case will match EXISTS filter and MATCH EMPTY filter.

Empty Strings

We want to allow empty strings as legal property values:

<user>
    <fullName></fullName>
</user>
<user>
    <fullName/>
</user>
{
    "@root" : "user",
    "fullName" : ""
}

This will be represented in Prism:

PrismObject(user)
    PrismObjectValue
        PrismProperty(fullName)
            PrismPropertyValue: realValue=""

There may be apparent confusion in XML with empty containers, e.g.:

<user>
    <fullName/>
    <assignment/>
</user>

But there is no problem here, both items have a value: The fullName is an ordinary property with string value (even though the string is empty). The assignment is a container with ordinary value, just the value has no subitems.

Illegal Cases

These cases are not allowed:

  • ItemValue with null as real value. E.g.

    PrismObject(user)
        PrismObjectValue
            PrismProperty(fullName)
                PrismPropertyValue: realValue=null

Matching Rules

Matching rules should apply to primitive values only - mostly strings, but some binary data may need matching rules as well (e.g. binary representation of IP address).

Use of matching rules for structured items will be deprecated, e.g. a use to match orig/norm part of PolyString.

Container values, their equivalence and identity

Larger set of issues references container id or their equivalence as a source

Possible solutions to container ID conflicts:

  • Never reuse container IDs inside object - current definition of id as long gives us up to 9,223,372,036,854,775,807 possible containers (adds/removals) inside object without overflowing

  • Use UUID as container ID - this would require 22 bytes per container in worst case (serialized as base64 UUID), instead of 1..11 bytes for long (larger numbers serialized using base64)

  • Cluster-wide singleton registry for assignment of container IDs for new objects - in order to prevent assignment of same container ID to two different processes

  • Natural identifiers - support for natural identifiers for containers eg.

    • containers with maxOccurs=1 - do not need identifier

    • container definition may specify which properties determines its identity

      • two containers represents same value only and only-if all properties are equal (semantically, not lexically)

Delta Semantics

Schema

  • Container presence - does presence of container is only for structural reasons (grouping of related attributes) or signifies behaviour