Flex Actions and plugins, Run Rules for Wizards and Actions and Event Handlers make use of runtime Expressions to dynamically modify behavior, for example you can use an expression to parse workflow variables to an action or evaluate a result for a run rule.
Dalet Flex supports the use of Spring Expression Language (SpEL). The same objects available in the JBPM context are also available in the Spring context, and thus can be used for Spring expressions as well. In newer versions of Dalet Flex, you should use SpEL. JEF plugins require the use of SpEL, while traditional plugins have traditionally used Expression language (EL) (however, most do support SpEL as well). Generally, SpEL will work for traditional and JEF plugins. However, regular expressions will not work for JEF plugins, so wherever possible use SpEL.
The main point of difference between SpEL and EL is the syntax, SpEL must start with#{
and end with}
. When Spring expressions are enabled, you must use#
instead of$
.
NOTE:
- Event handlers can only be configured using SpEL.
- Objects in the expression language are based on the internal Dalet Flex object model, and not the B2B API model.
- See the official Spring Expression guide for more information. This guide focuses on the advanced features of the Spring expression language.
- For workflow variables, you must use the syntax
#{variables['<variable name>']}
instead of${variables.<variable name>}
. - If applicable, you can combine SpEL with EL in different fields.
Expressions for Actions and Run Rules
You use expressions when configuring actions and run rules for wizards and actions.
The properties/fields available for use in expressions depend on the Java object backing the expression being evaluated. You can check the objects available by querying the internal Dalet Flex object model. For example, for a run rule for a job, valid objects are those available in the context of the job object.
Examples of Expressions for run rules and actions
The following is a partial list of examples of generic expressions that can be used in action configurations and run rules for actions and wizards.
Description | Spring Expressions | Expression Language |
---|---|---|
Returns the description of an asset | #{asset.description} |
|
Returns the ID of a user | #{user.id} |
${user.id} |
Returns the first name of a user | #{user.firstName} |
${user.firstName} |
Returns the last name of a user | #{user.lastName} |
${user.lastName} |
Returns the company of a user | #{user.company} |
${user.company} |
Returns the email address of a user | #{user.email} |
${user.email} |
Returns the name of a UDO | #{object.name} |
${object.name} |
Returns the title of an asset | #{asset.title} |
${asset.title} |
Returns active proxies for a file asset | #{asset.activeProxies} |
${asset.activeProxies} |
Returns the ID of a job | #{job.id} |
${job.id} |
Returns the due date of a job | #{job.dueDate} |
${job.dueDate} |
Returns the start date of a job | #{job.startDate} |
${job.startDate} |
Returns the end date of a job | #{job.endDate} |
${job.endDate} |
Returns the priority of a job | #{job.priority} |
${job.priority} |
Returns the current state of a job | #{job.jobState} |
${job.jobState} |
Returns the ID of a workflow | #{workflow.id} |
${workflow.id} |
Returns the ID of an event (Used on event handlers) | #{event.id} |
N/A |
A boolean expression on an event handler | #{event.object.variant.name == "Media"} |
|
User Enabled Event Handler |
Until Dalet Flex 2021.4.0: From Dalet Flex 2021.5.0: #{event.mioObject.id} |
N/A |
Password Reset Event Handler | Until Dalet Flex 2021.4.0: #{event.mioObject.name} From Dalet Flex 2021.5.0: #{event.mioObject.id} |
N/A |
Applies a run-rule expression in a Copy action details page | #{asset.mioObject.approved} |
${asset.mioObject.approved} |
Executes a Launch Workflow with an import action | #{variables['externalFileName']} |
${variables.externalFileName} |
Executes a Segmented Proxy action via a workflow | #{variables[‘videoAssetIds’]} |
${variables.videoAssetIds} |
Executes a Segmented Proxy action via a workflow | #{variables['audioAssetId']} |
${variables.audioAssetId} |
Obtains the value of a workflow variable with this name (This can be a string, object, or date) | #{variables['varName']} |
${variables.varName} |
Returns the current version of a workflow | #{workflow.version} |
${workflow.version} |
Examples of Run Rules for Wizards and Actions
Run rules typically evaluate to a parameter related to the context. For example, a run rule can be applied to a wizard so that the wizard is only displayed for a particular asset type or based on the value of a particular field. The wizard is only dispalyed if the expression evaluates to true. Similarly, you can apply a run rule to an action so that the action only runs if the expression evaluates to true.
The following is a list of real life examples of expressions used in run rules in wizards/actions. You must adapt your expressions for your environment.
Condition for showing the wizard/running the action for | Run Rule Expression |
A media asset with a variant = Video | #{object.type.name == "media-asset" && object.variant.name == "Video"} |
A media asset that has a metadata field called 'flex archived' set to true | #{object.type.name == "media-asset" && '@@flex-archived@@' == true} |
Audio, Video, Placeholder or image assets, that are NOT archived | #{(objectType.name == "media-asset" || objectType.name == "image-asset") && !asset.archived} |
Users with the IDs 506 or 514, or 410 or 15577 | #{user.id==506 || user.id==514 || user.id==410 || user.id==15577} |
Show the wizard when the asset is not a placeholder, and a Segemented Proxy Action can be launched for the asset. This is a useful wizard run-rule for a 'Regenerate Proxy' wizard when segmented proxies are used. |
#{mioObject.entity.isSegmentedProxyActionsAvailable && !asset.placeHolder} |
Collections | #{(objectType.name=="collection2")} |
Show the wizard if the asset is in a specific workspace called flex | #{asset.workspace.displayName == "flex"} |
Run the action in the context of a job (move, purge, proxy create actions etc) |
#{job!=null} |
Run the action in the context of a job Or for user with ID = 413 |
#{(job != null) || (user.role.id == 413)} |
Script Example for Wizard-run Rules
${object.type.name == "media-asset" && object.variant.name == "Video"}
${object.type.name == "media-asset" && '@@flex-archived@@' == true}
${object.type.name == "media-asset" && object.variant.name == "OTT Media" && !asset.published}
#{user.member.?[mioObject.name.contains("The Summit")].size() > 0}
${user.id == 195193}
${asset.placeHolder==true}
#{(objectType.name == "media-asset" || objectType.name == "image-asset") && !asset.archived}
${(object.type.pluralName=="MDA Templates" || object.type.pluralName=="Audio Templates" || object.type.pluralName=="Photo Templates")}
${(objectType.name=="collection2")}
#{user.mioObject.entity.role.displayName=="Admin" }
Spring Expressions for Event Handlers
You can ONLY use SpEL for configuring expressions for event handlers. You use Spring expressions to filter for events with specific values, or to ensure event handlers only run when certain fields are present.
You can also use expressions in configuration fields present in particular types of event handlers, for example for a Job Executor event handler.
Event objects have different structures, depending on the event type. E.g. A metadata modified event has a different structure to a password reset event structure. This means that writing an event handler expression is more complicated due to the plethora of different events and event data. Use a GET call to the REST API using an eventID to retrieve the event details and retrieve the event.json and view all available objects for that event.
Below is a non-exhaustive set of event fields and sub-fields accessible via Spring expressions. You should also be able to access most other fields present in the full JSON representation of the event. To do this, build out the expression as in the below examples, starting with the top levelevent
and adding each layer on the path to the field in question. Each layer on the path corresponds to each layer of data in the JSON event.
For example, consider the following JSON:
{
"event": {
"object": {
"id": 123
},
"anotherField": "someValue"
}
}
If you wanted to match against the value of theid
field, you would start atevent
, addobject
, and end inid
, giving you the pathevent.object.id
. You could then use this path in a Spring expression like so:#{event.object.id == 123}
, or#{event.object!=null&&event.object.id == 123}
to be null-safe (more information at the bottom of the page).
If you wanted to match against the value ofanotherField
, you could follow the same process to build the path to the field you would like to target; in this case, the path would beevent.anotherField
, which could then be used in a Spring expression like#{event.anotherField!=null&&event.anotherField.startsWith("some"}
. This expression would return match against all events with ananotherField
value beginning with “some”.
Selected event fields and examples for different event objects
Asset fields
Field | Expression Language Example | Notes |
---|---|---|
ID | #{event.asset!=null&&event.asset.id == 123} |
|
External IDs | #{event.asset != null && event.asset.externalIds != null && event.asset.externalIds.^[key == "particularExternalKey"] != null} |
Target assets that have a particularly-named external ID |
Media region | #{event.asset != null && event.asset.mediaRegion != null && event.asset.mediaRegion.sourceTimestampIn < 200000} |
Target assets that have a media region and source timestamp in of less than 200000 milliseconds |
Composition asset tracks | #{event.asset != null && event.asset.compositionAssetTracks != null && event.asset.compositionAssetTracks.size() > 2} |
Target assets that have more than two composition asset tracks |
Asset origin | #{event.asset != null && event.asset.assetOrigin == "Proxy"} |
Other possible asset origin options include “Ingest”, “Import”, “New”, etc. Please note that this match is case-sensitive |
Locked | #{event.asset != null && event.asset.locked == true} |
|
Parent asset | #{event.asset != null && event.asset.parentAsset != null && event.asset.parentAsset.id == 456} |
Good for targeting all children of a given asset |
Variant | #{event.asset != null && event.asset.variant != null && event.asset.variant.id == 789} |
Object fields
Field | Expression Language Example | Notes |
---|---|---|
ID | #{event.object != null && event.object.id == 123} |
|
Account ID | #{event.object != null && event.object.account != null && event.object.account.id == 456} |
|
Workspace ID | #{event.object != null && event.object.workspace != null && event.object.workspace.id == 789} |
|
Display name | #{event.object ! = null && event.object.displayName != null && event.object.displayName.startsWith("Common Prefix")} |
Targets objects that have display names starting with the given string value – this would be"Common Prefix" in the given example. Please note that this match is case-sensitive |
Object type fields
Field | Expression Language Example | Notes |
---|---|---|
ID | #{event.objectType != null && event.objectType.id == 123} |
|
Name | #{event.objectType != null && event.objectType.name == "Some Object Type"} |
Example names: “media-asset”, “image-asset” |
Display name | #{event.objectType != null && event.objectType.displayName == "Some Object Type Display Name"} |
Example display names: “Media Asset”, “Image Asset” |
Metadata supported (boolean) | #{event.objectType != null && event.objectType.metadataSupported == true} |
|
Attachments supported (boolean) | #{event.objectType != null && event.objectType.attachmentsSupported == false} |
|
Comments supported (boolean) | #{event.objectType != null && event.objectType.commentsSupported == true} |
User fields
Field | Expression Language Example | Notes |
---|---|---|
User ID | #{event.user != null && event.user.id == 123} |
|
User’s first name | #{event.user != null && event.user.firstName == "First"} |
|
User’s last name | #{event.user != null && event.user.lastName == "Last"} |
|
User’s role | #{event.user != null && event.user.role != null && event.user.role.id == 456} |
You can also access other role fields, such asid andname
|
Owner’s full name | #{event.ownerFullName == "John Doe"} |
Convenient way to match against a user’s full name |
Metadata fields
Create expressions that reference values in metadata fields in the metadata instance associated to the object that the event is generated for.
Expression Language Example | Description |
#{"@@editorial-approval@@" == "done"} | To match a string use quotes (single or double) for comparisons |
#{@@metadata-integer@@ == 123} | For an integer, you do not need quotes. This expression finds the first field named 'metadata-integer' in the metadata and then evaluate the expression. If it its value is 123, the expression evaluates to true and if it is not it evaluates to false. |
#{@@complex-1.metadata-integer@@ == 123} | Target a field by its path. This is useful when there are two sub-fields with the same name |
Event data
Event data – the section of the event containing data specifically tied to the event type – can be accessed using a method calledgetDataValue
, like so:event.getDataValue("someEventDataField").get()
.
It is often the case that users would like to filter events based on the content of nested event data fields. This occurs, for example, when checking the value of a taxonomy field change. Consider the following event data JSON snippet:
{
"eventData": [
{
"name": "asset-status",
"value": "{\"mode\":\"updated\",\"before\":\"Rejected\",\"after\":\"Approved\"}",
"type": "JSON"
}
]
}
Here, the event datavalue
field contains escaped, nested JSON. Let’s assume that the requirement is to only run the event handler whenafter
equalsApproved
in thevalue
field’s nested JSON. Unfortunately, we cannot access these fields using a path like we do other fields in the event (likeevent.object.id
,event.asset.displayName
, etc). Instead, we can use regex to target String values contained in thevalue
field. For the above example, that would look like this:#{event.getDataValue("media-status").get().value.matches("(.*)after(.*):(.*)Approved(.*)")}
. The(.*)
statements allow us to sidestep the issue of the escaped quotation marks, but they do so at the potential cost of reducing the precision of the regex. If using such an expression, be sure to test the event handler to make sure it behaves as expected in all scenarios.
Scenario | Expression Language Example |
---|---|
Check if field is present and non-blank | #{event.getDataValue('myEventDataField').isPresent() && event.getDataValue('myEventDataField').get().length > 0} |
Match specific value in escaped, nested JSON | #{event.getDataValue("media-status").get().value.matches("(.*)after(.*):(.*)Approved(.*)")} |
Check that a field DOES NOT match a specific value in escaped, nested JSON | #{!event.getDataValue("media-status").get().value.matches("(.*)mode(.*):(.*)updated(.*)")} |
Examples of Filters for Event Handlers
Condition for triggering the event handler | Filter |
The user is an internal Flex user (not a SSO user) NB: not working on any flex recent release when used in the mail "forgotten" password filter list |
#{event.user.userType != "EXTERNAL"} |
One of three metadata fields is not set to NULL i.e. If one of three metadata fields has been 'set' to a meaningful value |
#{event.EventData["assetMetadataField1"] != null || event.EventData["assetMetadataField2"] != null || event.EventData["assetMetadataField3"] != null} |
When a metadata field backed by a taxonomy is changed by a user. Note: media-status is the metadata field name and the number is the FlexID for the selected taxonomy. |
#{event.getDataValue("media-status").get().value.matches("(.*)after(.*):(.*)[49056661](.*)")} |
Technical notes
- To prevent null pointer exceptions (NPE) in the logs, you can add a null check to the expressions to ensure that that the field is not null before continuing. The null check in the event examples above is added using event.object != null && to the expression.
- SpEL provides many convenience methods for collections (lists, sets, maps, etc). You can use these convenience methods when targeting event fields that are collections, such as external IDs, placed media regions, and so on. There are some usage examples on this page, but you can also refer to the official Spring documentationfor more advanced functionality in this area.
Comments
0 comments
Please sign in to leave a comment.