@ben thanks for sharing. Just came across this and I had ended up with very similar code as you, but with a few adjustments that I thought were cleaner in the end:
For anyone that comes across similar needs for Camunda usage.
There seems to be issues with placing the imports below the CustomScriptAction annotation. Have run into multiple scenarios where code was not executing as expected, but threw no errors. Seems to be partially from the way CustomScriptActions are pre-processed through AST transformations, Freemarker scripts, and likely other “magic” under the hood that RPA express is implementing.
Regardless, we end up with the following
Fetch and Lock:
import groovy.json.JsonBuilder
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
@CustomScriptAction(
output = 'task_query_result'
)
def customScript() {
try{
URL url = new URL('http://MyCamundaServer:8080/engine-rest/external-task/fetchAndLock')
HttpURLConnection http = (HttpURLConnection) url.openConnection()
http.setRequestMethod('POST')
http.setConnectTimeout(5000)
http.setReadTimeout(30000)
http.setRequestProperty('Content-Type', 'application/json; charset=UTF-8')
http.setRequestProperty("Accept", "application/json");
http.setDoInput(true)
http.setDoOutput(true)
String body = '''
{
"workerId":"workfusion-robot",
"maxTasks": 1,
"usePriority": true,
"topics":[
{
"topicName": "some-topic",
"lockDuration": 20000,
"variables": ["someVar1", "someVar2"]
}
]
}
'''
JsonSlurper slurper = new JsonSlurper()
def json = new JsonBuilder(slurper.parseText(body)).toPrettyString()
http.getOutputStream().write(json.getBytes('UTF-8'))
def responseCode = http.getResponseCode()
if (responseCode != 200){
throw new Exception('Did not receive response code 200 from Camunda')
}
def response = http.getInputStream()
def tasks = slurper.parse(response)
if (tasks.size() == 0) {
task_query_result = RString.of('')
} else {
task_query_result = RString.of(JsonOutput.toJson(tasks[0]))
}
} catch(all){
task_query_result = RString.of("Error: ${all.getMessage()}")
}
}
Notice how I went with storing the responses as Strings rather than your model of a Table. I did this because I noticed that the “Expressions” in RPA Express are actually java/groovy evals, thus we can take advantage of that in our logic handling!!
So because the Custom Script can only have 1 returned variable, we will send the entire JSON body into the “task_query_result” variable, which is defined as a String in the Recorder Variables.
Then we use the Constant Variable
action that points to the Recorder Variable task_id
and a “set value” of: ${new groovy.json.JsonSlurper().parseText(task_query_result.toString()).id}
. We use the toString() to just double ensure no weirdness from the RPA Express classes of the RString stuff…
So we can do this for variable needed that was contained within the Json response that was stored.
Then We do our work as per the image above, where you are clicking through a website or whatever.
We eval the response and if everything was good, we return our completion to camunda with:
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
@CustomScriptAction(
input = ['task_id', 'some_recorder_var'],
output = 'task_completion_result'
)
def customScript() {
try{
String taskId = task_id.toString()
String someRecorderVar = some_recorder_var.toString()
URL url = new URL("http://MyCamundaServer:8080/engine-rest/external-task/${taskId}/complete")
HttpURLConnection http = (HttpURLConnection) url.openConnection()
http.setRequestMethod('POST')
http.setConnectTimeout(5000)
http.setReadTimeout(30000)
http.setRequestProperty('Content-Type', 'application/json; charset=UTF-8')
http.setRequestProperty("Accept", "application/json")
http.setDoInput(true)
http.setDoOutput(true)
String body = $/
{
"workerId":"workfusion-robot",
"variables":
{
"issueCreated": {"value": "${someRecorderVar}"}
}
}
/$
JsonSlurper slurper = new JsonSlurper()
def json = new JsonBuilder(slurper.parseText(body)).toPrettyString()
http.getOutputStream().write(json.getBytes('UTF-8'))
def responseCode = http.getResponseCode()
if (responseCode != 204){
throw new Exception("Did not get 204 back from Camunda Task Completion: ${response}")
}
} catch(all){
task_completion_result = RString.of('error ' + all.getMessage())
}
}
Notice the use of $/ ... /$
which allows multi-line strings with groovy ${}
expression variables. No need for the manual backslashes!
With this setup, you can process JSON within the custom action, as well as eval the json from the RPAExpress “expressions” such as doing a IF
action that evaluated a value within the JSON, rather than having to pollute the Recorder Variables.