Back End Scripting
Introduction
Scripting can be used in various places like a Script Task of a process or a Script Task of a case as well as within a service registry definition using script.
A JSR-223 compliant scripting language like JavaScript or Groovy can be used for the script itself and Flowable exposes a scripting API into the scripting context as well where you will have access to various utilities as well as to create JSON objects and get access to services, request input variables and register output parameters, depending on your context of course.
This documentation is all about the Flowable scripting API, which is exposed using flw
.
Input and Output
In a script you can get input values using flw.getInput(name)
, depending on the context, the variable with the requested
name is returned or an input parameter with that name, respectively.
The same works with flw.setOutput(name, value)
where a variable value can be set or an output parameter value can be registered.
The following methods are available:
flw.getInput(name)
depending on the context, the variable with the requested name is returned or an input parameter with that name, respectively.flw.setOutput(name, value)
variable value is set or an output parameter value can is registered.flw.setTransientOutput(name, value)
transient variable value is set.flw.setLocalOutput(name, value)
a variable value is set to the local scope.
Examples for a script task:
flw.getInput('foo');
will return the variable namedfoo
.flw.setOutput('bar', myBarValue);
will store a new variable namedbar
with the value provided by the local scripting-variable namedmyBarValue
.
Examples for a registry service with scripting:
flw.getInput('foo');
will return the mapped input parameter namedfoo
.flw.setOutput('bar', myBarValue);
will register the value provided by the local scripting variablemyBarValue
as the output parameter namedbar
.
BPMN Errors
The Scripting API supports throwing BPMN Errors using the following methods:
flw.bpmn.throwError('ERROR_CODE')
flw.bpmn.throwError('ERROR_CODE', 'Error Message')
BPMN Errors can be handled using error boundary events or error event subprocesses in BPMN models, which make them a powerful tool for model based error handling, without java code modifications.
The util methods are a convenient equivalent of throw new org.flowable.engine.delegate.BpmnError('ERROR_CODE')
.
Flowable Errors
The Scripting API supports throwing Flowable Specific Errors using the following methods:
flw.error.throwForbidden('Forbidden Message')
- Throws a flowable forbidden exception with the given message. This will be mapped to a 403 HTTP status code.flw.error.throwIllegalArgument('Illegal Argument Message')
- Throws a flowable illegal argument exception with the given message. This will be mapped to a 400 HTTP status code.flw.error.throwNotFound('Not Found Message')
- Throws a flowable object not found exception with the given message. This will be mapped to a 404 HTTP status code.
JSON Utilities
The scripting API also supports various utilities around JSON object handling like creating a JSON object or array or converting a JSON string into a JSON object structure.
You can access those utilities through flw.json
.
To create a new, empty JSON object, use flw.json.createObject();
and store the result as a local variable or use the fluent API of the returned
JSON object to create its value.
Json Objects with Simple Values
A simple Json object using just values, but without nested or list values, can be created as follows:
Examples:
var myJson = flw.json.createObject();
myJson.putString('name', 'Sample Json object');
myJson.putInteger('sum', 100);
myJson.putBoolean('verified', true);
This example could also be written as:
var myJson = flw.json.createObject()
.putString('name', 'Sample Json object')
.putInteger('sum', 100)
.putBoolean('verified', true);
Or, if used as an output value:
flw.setOutput('myJsonOutputParameter', flw.json.createObject()
.putString('name', 'Sample Json object')
.putInteger('sum', 100)
.putBoolean('verified', true));
There are different ways to represent data with scripts:
- Groovy/JavaScript variables (in the following focused on JavaScript for simplification)
- JSON
- Flowable variables
In JavaScript you can create object structure and add different elements to those objects, including for example dates.
E.g.: {name: 'Sample Json object', myDate: new Date()}
Converting this to JSON will then result in something like the following: {"test":"2024-01-17T05:53:01.880Z"}
.
This can be assigned in JavaScript to a variable, however it still does not make every JavaScript variable a valid JSON.
E.g. {test: () => { return 'test' }}
will be a valid object in JavaScript, but converting it to JSON results in an empty object {}
.
The Flowable flw.json
API is language agnostic across different scripting languages with backwards compatibility.
The JavaScript execution comes from the Nashorn engine and might differ between different Java version and/or versions of the Nashorn engine available on the classpath.
It is also possible to create a JSON structure directly with JavaScript/Groovy, just be aware that this depends on the execution engine.
The following example would use the JavaScript engine to create an object, convert it to a JSON and then add it as the Flowable JSON variable testJson
:
flw.setOutput("testJson",
flw.json.stringToJson(
JSON.stringify({name: 'Sample Json object', test: new Date()})
)
);
Nested Json Objects
Nested objects can also be created easily:
var myJson = flw.json.createObject()
.putString('name', 'Sample Json object');
myJson.createChildObject('nestedObject')
.putString('nestedObjectName', 'Nested Json object');
The method createChildObject
will create a new child Json object and add it to the current object
(where the method is invoked from) using the provided field name.
Pay attention to the return values; createObject()
will return the root Json object, but createChildObject
always just returns the newly created child object for further processing like adding values. If you need to eventually
use the root object, make sure to keep a variable with the returned root Json object and not just the latest nested one.