Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Introduction

For the wishlist item

Jira Legacy
serverSystem JIRA
serverIdb13bfa7d-a627-37d0-9f27-5b1bea629f5c
keyMWISH-423
we want to introducte an expression language in order the describe the dynamical task requested by the customer.

Requirements

When executing a batch the new metadata of the item should be able to be determined by

  • The previous/current metadata of the item

  • Combinations of fields

  • Conditions

  • Textual operations

Solution

...

Introduced in version 23.1

Introduction

Using Metadata Expressions a new batch task is available and named BatchExpressionTemplatesTask. It takes as an argument a list of metadata sidecar e.g.-like arguments. An example of such metadata sidecar is

Code Block
{
    "Descriptive": {
       "Title": "Metadata Expression Analysis"
    },#{R('Descriptive.Title').toUpperCase()}",
       "Description": "#{R('Descriptive.Title') + ': ' + R('Dynamic.CustomDescription')}",
     "Dynamic  "Keywords": {"Keyword": "#{R('Dynamic.CustomTag')}"}
    },
    "CustomFieldDynamic": {
 "Some  value"     }
}

This metadata sidecar can now use a strict Spring Expression Language (Spel) subset to perform more complex operations. You can put one or more expressions #{...} in the JSON or XML. Inside an expression, you can reference the metadata using R(<Dotted key>) or record(<Dotted key>) for example R('Descriptive.Title') or record('Descriptive.Title').

Info

The system ensures the result after evaluating the expression it is correctly escaped

Example input

"Orientation": "#{(R('Technical.Width') > R('Technical.Height')) ? 'Horizontal' : 'Vertical'}",
        "AdditionalInformation": "My custom field"
    }
}

Merging

When the templated sidecar is evaluated against a record it will result for example in the following metadata sidecar

The expression for each JSON property must evaluate to one of the following types

  • String is converted into a JSON string

  • List<String> is converted into a JSON array

  • Map<String> is converted into a
    Code Block
    {
        "Descriptive": {
           "Title": "R('Descriptive.Title').toUpperCase()MY TEST FILE",
           "Description": "R('Descriptive.Title') + ': ' + R('Dynamic.CustomField')My test file: this is a test file",
           "Keywords": {"Keyword": "{R('Dynamic.CustomField')}"["My custom tag"]}
        },
        "Dynamic": {
            "CustomFieldOrientation": "R('Dynamic.CustomField2') == 'X' ? 'Option A' : 'Option B'"Horizontal",
            "AdditionalInformation": "My custom field"
        }
    }
    Tip

    This metadata sidecar will then be merged against the record using the same rules as when MediaHaven Rest API - Updating a record.

    Output after evaluating the expression

    After evaluating all expressions in the input metadata sidecar, the result is a new metadata sidecar in JSON. The conversion follows the following rules

    Output after evaluating the expression

    Conversion into JSON

    String

    JSON string

    Boolean

    JSON boolean

    Long

    JSON number

    List<String>

    JSON array

    Map<String>

    JSON object

    Map<String,List<String>>

    ...

    JSON object containing JSON arrays

    All special characters are automatically escaped

    The output of the metadata accessor

    The output of the metadata accessor R or record is the following depending on which field type the dotted key refers to:

    ...

    Level

    ...

    Case

    ...

    Effect

    ...

    Example Expression

    ...

    Example Output

    ...

    Top

    ...

    SimpleField

    ...

    String

    ...

    R('Descriptive.Title')

    ...

    My title

    ...

    Top

    ...

    ListField

    ...

    List of Strings

    ...

    R('Descriptive.Keywords')

    ...

    ["A", "B", "C"]

    ...

    Top

    ...

    MapField

    ...

    Map of Strings

    ...

    R('Structural.Versioning')

    ...

    {"Status": "HEAD", "Version": "2"}

    ...

    Top

    ...

    MultiItemField

    ...

    Map of List of Strings

    ...

    R('Descriptive.Authors')

    ...

    {"Authors": ["Cedric"], "Director": ["Alice", "Bob"]}

    ...

    Top

    Others

    ...

    Not allowed

    ...

    Sub

    ...

    Child of ListField

    ...

    List of Strings

    ...

    R('Descriptive.Keywords.Keyword')

    ...

    ["A", "B", "C"]

    ...

    Sub

    ...

    Child of MultiItemField

    ...

    List of Strings

    ...

    R('Descriptive.Authors.Director')

    ...

    ["Alice", "Bob"]

    ...

    Sub

    ...

    Child of MapField

    ...

    String

    ...

    R('Structural.Versioning.Status')

    ...

    HEAD

    ...

    Sub

    ...

    Other

    ...

    Not allowed

    The R takes an optional second argument, which is the default value. When it is not specified the default value is the empty string.

    Security

    The available features of SPel are described here: https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/expressions.html. We must disable all features except

    • Literal expressions

    • Boolean and relational operators

    • Method invocation

    • Inline lists

    • Ternary operator

    • The method name “R” or “record”

    ...

    Notice how the string "#{R('Dynamic.CustomTag')}" is evaluated into an array ["My custom tag"]. The end result is a valid metadata sidecar for “Keywords” namely "Keywords": {"Keyword": ["My custom tag"]} whereas before evaluating the expression "Keywords": {"Keyword": "#{...}"} is not a strictly valid metadata sidecar because the value of "Keyword" must be an array and not a string.