Edit this page

Placeholders

Placeholders may be used at several places in Ditto where something should be resolved by a variable.
The general syntax of a placeholder is {{ prefix:name }}. Which placeholder values are available depends on the context where the placeholder is used.

Entity Placeholder

Placeholder Description
{{ entity:id }} full ID composed of ‘‘namespace’’ + ‘’:’’ as a separator + ‘‘name’’ for things and policies
{{ entity:namespace }} Namespace (i.e. first part of an ID) for things and policies
{{ entity:name }} Name (i.e. second part of an ID ) for things and policies

Thing Placeholder

Placeholder Description
{{ thing:id }} full ID composed of ‘‘namespace’’ + ‘’:’’ as a separator + ‘‘name’’
{{ thing:namespace }} the namespace (i.e. first part of an ID) of the related thing
{{ thing:name }} the name (i.e. second part of an ID ) of the related thing

Thing JSON Placeholder

Placeholder Description
{{ thing-json:<json-pointer> }} Value (in string representation) of the JSON identified by the provided ‘‘json-pointer’’ in JsonPointer notation - e.g., thing-json:attributes/location for the “location” attribute or thing-json:features/temperature/properties/value for the temperature property.

Feature Placeholder

Placeholder Description
{{ feature:id }} the ID of the feature (only available if the processed signal was related to a feature)

Policy Placeholder

Placeholder Description
{{ policy:id }} full ID composed of ‘‘namespace’’ + ‘’:’’ as a separator + ‘‘name’’
{{ policy:namespace }} the namespace (i.e. first part of an ID) of the related policy
{{ policy:name }} the name (i.e. second part of an ID ) of the related policy

Policy Entry Placeholder

Placeholder Description
{{ policy-entry:label }} label of the policy entry in which the token integration subject is injected

Connection Placeholder

Placeholder Description
{{ connection:id }} the ID of the connection which receives/publishes a signal

Header Placeholder

Placeholder Description
{{ header:<header-name> }} Value of the header with the given name. For incoming signals the headers of the used protocol are used. For outgoing values the Ditto protocol headers are used.(both case-insensitive)

Topic Placeholder

Placeholder Description
{{ topic:full }} full Ditto Protocol topic path
in the form {namespace}/{entityName}/{group}/
{channel}/{criterion}/{action-subject}
{{ topic:namespace }} Ditto Protocol topic namespace
{{ topic:entityName }} Ditto Protocol topic entity name
{{ topic:group }} Ditto Protocol topic group
{{ topic:channel }} Ditto Protocol topic channel
{{ topic:criterion }} Ditto Protocol topic criterion
{{ topic:action }} Ditto Protocol topic action
{{ topic:subject }} Ditto Protocol topic subject (for message commands)
{{ topic:action-subject }} either Ditto Protocol topic action or topic subject (for message commands)

Resource Placeholder

Placeholder Description
{{ resource:type }} the type of the Ditto Protocol path , one of: "thing" "policy" "message" "connection"
{{ resource:path }} the affected resource’s path being the Ditto Protocol path in JsonPointer notation, e.g. / when a complete thing was created/modified/deleted

Request Placeholder

Placeholder Description
{{ request:subjectId }} the first authenticated subjectId which sent the command / did the request

Time Placeholder

Placeholder Description
{{ time:now }} the current timestamp in ISO-8601 format as string in UTC timezone
{{ time:now_epoch_millis }} the current timestamp in “milliseconds since epoch” formatted as string
{{ time:now<+-offset> }} the current timestamp in ISO-8601 format as string in UTC timezone plus or minus the offset in format <integer><unit> where unit is one of ms s m h d w mo y
{{ time:now_epoch_millis<+-offset> }} the current timestamp in “milliseconds since epoch” formatted as string plus or minus the offset in format <integer><unit> where unit is one of ms s m h d w mo y
{{ time:now[<truncation-unit>] }} the current timestamp in ISO-8601 format as string in UTC timezone, truncated to the unit defined in square brackets, being one of ms s m h d w mo y
{{ time:now_epoch_millis[<truncation-unit>] }} the current timestamp in “milliseconds since epoch” formatted as string, truncated to the unit defined in square brackets, being one of ms s m h d w mo y
{{ time:now<+-offset>[<truncation-unit>] }} the current timestamp in ISO-8601 format as string in UTC timezone plus or minus the offset in format <integer><unit> where unit is one of ms s m h d w mo y, truncated to the unit defined in square brackets, being one of ms s m h d w mo y
{{ time:now_epoch_millis<+-offset>[<truncation-unit>] }} the current timestamp in “milliseconds since epoch” formatted as string plus or minus the offset in format <integer><unit> where unit is one of ms s m h d w mo y, truncated to the unit defined in square brackets, being one of ms s m h d w mo y

Examples - assuming that the now timestamp is: 2024-01-06T14:23:42.123Z

{{ time:now }}        # current ts:                                       2024-01-06T14:23:42.123Z
{{ time:now+1h }}     # current ts, +1 hour:                              2024-01-06T15:23:42.123Z
{{ time:now-7d }}     # current ts, -7 days:                              2023-12-31T14:23:42.123Z
{{ time:now[h] }}     # current ts, truncated to the hour:                2024-01-06T14:00:00.000Z
{{ time:now[d] }}     # current ts, truncated to the day:                 2024-01-06T00:00:00.000Z
{{ time:now-25m[m] }} # current ts, -25 minutes, truncated to the minute: 2024-01-06T13:58:00.000Z
{{ time:now+3d[s] }}  # current ts, +3 days, truncated to the second:     2024-01-09T14:23:42.000Z

The same offset and truncation can be done with the now_epoch_millis.

JWT Placeholder

Placeholder Description
{{ jwt:<claim-pointer> }} Any standard or custom claims in the body of the authenticated JWT in JsonPointer notation - e.g., jwt:sub for the JWT “subject” or jwt:extra/roles for (potentially multiple) “roles” extracted from a JsonObject in the JWT named extra.
JWT claims being JSON arrays are expanded (each value of the array is added) and provided functions are performed on each array element.

Scope: Entity creation / modification

Whenever creating or modifying things or policies, the following placeholders may be used:

Scope: OpenID Connect configuration

When configuring OpenID connect providers in a Ditto setup, the jwt: placeholder can be used in order to extract certain claims from the JWT in order to use them as authorization subjects for Ditto’s policy based authorization.

The following placeholders may be used inside the configuration file:

In combination with functions, use of this placeholder can provide and modify the subjects to extract from a JWT in a very powerful way.
The fn:split(' ') function may for example be used in order to further split the default claim “scope”, which is by default a whitespace separated list of scopes, as an array, producing multiple entries for each provided scope.

Example:

Assuming the provided JWT looks like this:

{
  "sub": "u123456789",
  "iss": "https://<the-issuer-domain>/",
  "exp": 1490922820,
  "iat": 1490886820,
  "email": "john.doe@eclipse.org",
  "aud": "client-id-0815",
  "scopes": "openid email",
  "extra": {
    "roles": [
      "administrator",
      "super-moderator",
      "moderator"
    ]
  }
}

Applied on the example JWT, the following jwt: placeholders in combination with functions are resolved in the following way:

  • {{ jwt:sub }} - resolves to "u123456789"
  • {{ jwt:sub }}@{{ jwt:aud }} - resolves to "u123456789@client-id-0815"
  • {{ jwt:extra/roles }} - resolves to 3 entries: "administrator", "super-moderator" and "moderator"
  • {{ jwt:scopes | fn:split(' ') }} - resolves to 2 entries: "openid" and "email"
  • {{ jwt:extra/roles | fn:filter('like','*moderator') }}@{{ jwt:aud }} - resolves to 2 entries: "super-moderator@client-id-0815" and "moderator@client-id-0815"

Scope: Policy actions

In policy actions, the following placeholders are available in general:

Scope: RQL expressions when filtering for Ditto Protocol messages

When using RQL expressions in scope of either change notifications or subscriptions for live messages, the following placeholders are available in general:

Scope: Websocket Signal Enrichment

When declaring extra fields which should be enriched to a published signal for a Websocket connection, the following placeholders are available in general:

Scope: SSE Signal Enrichment

When declaring extra fields which should be enriched to a published signal for an SSE subscription, the following placeholders are available in general:

Scope: Connections

In connections, the following placeholders are available in general:

Examples

For a topic path with the intention of creating a Thing org.eclipse.ditto/device-123/things/twin/commands/create these placeholders would be resolved as follows:

Placeholder Resolved value
topic:full org.eclipse.ditto/device-123/things/twin/commands/create
topic:namespace org.eclipse.ditto
topic:entityName device-123
topic:group things
topic:channel twin
topic:criterion commands
topic:action create
topic:subject
topic:action-subject create

For a topic path with the intention of sending a message to a Thing org.eclipse.ditto/device-123/things/live/messages/hello.world these placeholders are resolved as follows:

Placeholder Resolved value
topic:full org.eclipse.ditto/device-123/things/live/messages/hello.world
topic:namespace org.eclipse.ditto
topic:entityName device-123
topic:group things
topic:channel live
topic:criterion messages
topic:action
topic:subject hello.world
topic:action-subject hello.world

Function expressions

Whenever placeholders can be used (e.g. for connections), function expressions may additionally be specified.

The syntax of such function expressions are specified similar to a UNIX pipe, e.g.:

{{ thing:name | fn:substring-before('-') | fn:default('fallback') | fn:upper() }}

Normally, the first expression in such a pipeline would be a placeholder to start with, in the example above thing:name.
Functions could follow it separated by the pipe (|) symbol - each function in the pipeline receives the value of the previous expression (which may also be empty).
A function in the beginning of a pipeline would get empty as its input.

The function either contains no parameters or contains parameters which are either string constants or could also be placeholders again.

Function library

The following functions are provided by Ditto out of the box:

Name Signature Description Examples
fn:filter (String filterValue, String rqlFunction, String comparedValue) Removes the result of the previous expression in the pipeline unless the condition specified by the parameters is satisfied.
The first parameter filterValue may also be omitted in which case the 2 passed parameters will be appplied on the previous pipeline expression.
fn:filter('like','allowlist1|foobar|include')
fn:filter(header:response-required,'eq','true')
fn:filter(header:response-required,'exists')
fn:filter(header:response-required,'exists','false')
fn:default (String defaultValue) Provides the passed defaultValue when the previous expression in a pipeline resolved to empty (e.g. due to a non-defined header placeholder key).
Another placeholder may be specified which is resolved to a String and inserted as defaultValue.
fn:default('fallback')
fn:default("fallback")
fn:default(thing:id)
fn:substring-before (String givenString) Parses the result of the previous expression and passes along only the characters before the first occurrence of givenString.
If givenString is not contained, this function will resolve to empty.
fn:substring-before(':')
fn:substring-before(":")
fn:substring-after (String givenString) Parses the result of the previous expression and passes along only the characters after the first occurrence of givenString.
If givenString is not contained, this function will resolve to empty.
fn:substring-after(':')
fn:substring-after(":")
fn:lower () Makes the String result of the previous expression lowercase in total. fn:lower()
fn:upper () Makes the String result of the previous expression uppercase in total. fn:upper()
fn:trim () Trims the String result of the previous expression, removing leading and trailing whitespaces. fn:trim()
fn:url-encode () Applies URL encoding to the String result of the previous expression. fn:url-encode()
fn:url-decode () Applies URL decoding to the String result of the previous expression. fn:url-decode()
fn:base64-encode () Applies Base64 encoding to the String result of the previous expression. fn:base64-encode()
fn:base64-decode () Applies Base64 decoding to the String result of the previous expression. fn:base64-decode()
fn:delete () Deletes the result of the previous pipeline expression unconditionally. Any following expressions are ignored. fn:delete()
fn:replace (String from, String to) Replaces a string with another using Java’s String::replace method. fn:replace('foo', 'bar')
fn:split (String separator) Splits the previous pipeline using the passed separator resulting an “array” pipeline output containing several elements.
May only be used in combination with the JWT placeholder as input placeholder.
fn:split(' ')
fn:split(',')
fn:join (String delimiter) Joins the previous pipeline elements (when they were an array) resulting a single string pipeline output delimited with the passed delimiter. fn:join(':')
fn:join(',')

RQL functions

The following RQL functions are available for fn:filter

Name Signatures Description
eq (String filterValue, 'eq', String comparedValue),
('eq', String comparedValue)
If 3 parameters are passed in, the function filters on the first parameter being equal to the last.
If 2 parameters are passed in, the function filters the previous pipeline element being equal to the last parameter.
ne (String filterValue, 'ne', String comparedValue),
('ne', String comparedValue)
If 3 parameters are passed in, the function filters on the first parameter being not equal to the last.
If 2 parameters are passed in, the function filters the previous pipeline element being not equal to the last parameter.
exists (String filterValue, 'exists', String true|false),
('exists', String true/false),
('exists')
If 3 parameters are passed in, the function filters on the first parameter being existent/non-existent.
If 2 parameters are passed in, the function filters the previous pipeline element being being existent/non-existent.
If 1 parameter is passed in, the function filters the previous pipeline element being true.
like (String filterValue, 'like', String regex),
('like', String regex)
If 3 parameters are passed in, the function filters on the first parameter matching the last.
If 2 parameters are passed in, the function filters the previous pipeline element matching the last parameter.

The like function can be used with different expressions:

  • * : One or more arbitrary characters
  • ? : One arbitrary character
  • | : Element prior to the operator OR element after the operator
Tags: connectivity