How to overwrite process variable in UserTask

Hi,

I’m desperately trying to convert my workflows from Activiti to flowable 6.5.0.

Right now, I rewrote the whole workflow in Flowable Modeler to make sure, there is no unsupported legacy code in there.

My Problem is, that I am unable to update a process variable with a UserTask.

Example:

  • variable “foo” is defined in the start form. It get’s written to the process context as variable “foo”
  • In UserTask1, “foo” is defined again, taking the value from “foo” in process context
  • “foo” is updated via the form, but the change is never written to the process context
  • UserTask2 sees the old value of “foo” (set by the start event)

In Activiti I was able to set the process variables in a ScriptTaskListener containing:

task.execution.setVariables(task.getVariables());

In flowable, (using org.flowable.engine.impl.bpmn.listener.ScriptTaskListener) “task.execution” is not defined. “execution” is not defined neither. I tried to use an expression

${task.execution.setVariables(task.getVariables())} 

or

${task.execution.setVariables(task.getVariables())}

with no luck.

I can set non-existing process variables with task.setVariable(“foo1”,“bar1”). But it does not update existing variables.

Here is an example process:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
<process id="testprocess" name="Testprocess" isExecutable="true">
  <startEvent id="startEvent1" flowable:formFieldValidation="true">
    <extensionElements>
      <flowable:formProperty id="foo" name="Foo" type="string" required="true"></flowable:formProperty>
    </extensionElements>
  </startEvent>
  <userTask id="usertask1" name="UserTask1" flowable:formFieldValidation="true">
    <extensionElements>
      <flowable:formProperty id="foo" name="Foo" type="string" variable="foo" required="true"></flowable:formProperty>
    </extensionElements>
  </userTask>
  <sequenceFlow id="sid-CEC2D628-44B5-43C8-8E2C-30A9897F5CD5" sourceRef="startEvent1" targetRef="usertask1"></sequenceFlow>
  <userTask id="usertask2" name="UserTask2" flowable:formFieldValidation="true">
    <extensionElements>
      <flowable:formProperty id="foo" name="Foo" type="string" variable="foo"></flowable:formProperty>
    </extensionElements>
  </userTask>
  <sequenceFlow id="sid-1556A096-DA7C-4059-B478-74BBF8A23B86" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
  <endEvent id="sid-0CAB5176-C1A5-4CFC-B1FE-A78007C0B601"></endEvent>
  <sequenceFlow id="sid-760B0226-F513-4E6F-A786-DF0E311602E0" sourceRef="usertask2" targetRef="sid-0CAB5176-C1A5-4CFC-B1FE-A78007C0B601"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_testprocess">
  <bpmndi:BPMNPlane bpmnElement="testprocess" id="BPMNPlane_testprocess">
    <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
      <omgdc:Bounds height="30.0" width="30.0" x="165.0" y="161.01157054276433"></omgdc:Bounds>
    </bpmndi:BPMNShape>
    <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
      <omgdc:Bounds height="80.0" width="100.0" x="292.7777090975237" y="136.01157054276433"></omgdc:Bounds>
    </bpmndi:BPMNShape>
    <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
      <omgdc:Bounds height="80.0" width="100.0" x="480.0" y="136.01157054276433"></omgdc:Bounds>
    </bpmndi:BPMNShape>
    <bpmndi:BPMNShape bpmnElement="sid-0CAB5176-C1A5-4CFC-B1FE-A78007C0B601" id="BPMNShape_sid-0CAB5176-C1A5-4CFC-B1FE-A78007C0B601">
      <omgdc:Bounds height="28.0" width="28.0" x="645.0" y="162.01157054276433"></omgdc:Bounds>
    </bpmndi:BPMNShape>
    <bpmndi:BPMNEdge bpmnElement="sid-CEC2D628-44B5-43C8-8E2C-30A9897F5CD5" id="BPMNEdge_sid-CEC2D628-44B5-43C8-8E2C-30A9897F5CD5">
      <omgdi:waypoint x="194.9499993102127" y="176.01157054276433"></omgdi:waypoint>
      <omgdi:waypoint x="292.7777090975237" y="176.01157054276433"></omgdi:waypoint>
    </bpmndi:BPMNEdge>
    <bpmndi:BPMNEdge bpmnElement="sid-1556A096-DA7C-4059-B478-74BBF8A23B86" id="BPMNEdge_sid-1556A096-DA7C-4059-B478-74BBF8A23B86">
      <omgdi:waypoint x="392.72770909751057" y="176.01157054276433"></omgdi:waypoint>
      <omgdi:waypoint x="480.0" y="176.01157054276433"></omgdi:waypoint>
    </bpmndi:BPMNEdge>
    <bpmndi:BPMNEdge bpmnElement="sid-760B0226-F513-4E6F-A786-DF0E311602E0" id="BPMNEdge_sid-760B0226-F513-4E6F-A786-DF0E311602E0">
      <omgdi:waypoint x="579.949999999939" y="176.01157054276433"></omgdi:waypoint>
      <omgdi:waypoint x="645.0" y="176.01157054276433"></omgdi:waypoint>
    </bpmndi:BPMNEdge>
  </bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>

I would appreciate any help on this.

That task.execution worked, was a side-effect (it wasn’t the intention).
Flowable doesn’t have the execution as a getter anymore (as it led to many subtle bugs).

However, you can do task.setVariables(). They will be set on the process instance level.

Hi, thanks for your answer.

task.setVariables() does not work for already existing process variables. Neither does task.setVariable(“foo”,“bar1”), what is called by setVariables(), as far as I know.

Ok, I’m guessing there’s something other going on in my processEngine, which is embedded in an Identity Management system.

Apparently (I don’t know if that is possible), there exists another VariableScope between task and execution. So the variable changes are promoted to the parent scope, but not the execution scope.

Is there any way to get hold of either the parent scope or execution scope in ScriptTaskListener? Or is there a possibility to explicitely propagate the variable change to the higher level?

If that doesn’t work, there indeed will be something custom in between that is stopping propagation.

The Flowable classes all propagate upwards (e.g. task → process instance), so it seems your custom logic doesn’t do that? It probably should, for proper working.

The access to the parent is protected on the Task: see flowable-engine/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/VariableScopeImpl.java at main · flowable/flowable-engine · GitHub, so you won’t be able to access it directly in the script.

The only workaround I can think of right now is doing the old lazy loading programmatically in the script:
task.getExecutionId() and then CommandContextUtil.getExecutionEntityManager().findById(executionId). This will give you the Execution object.

Unfortunally, no luck, CommandContextUtil is not defined in that context:

Caused by: org.flowable.common.engine.api.FlowableException: problem evaluating script: javax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: CommandContextUtil for class: Script12
    at org.forgerock.openidm.workflow.activiti.osgi.FlowableOsgiScriptingEngines.evaluate(FlowableOsgiScriptingEngines.java:74)
    at org.forgerock.openidm.workflow.activiti.osgi.FlowableOsgiScriptingEngines.evaluate(FlowableOsgiScriptingEngines.java:49)
    at org.flowable.engine.impl.bpmn.listener.ScriptTaskListener.notify(ScriptTaskListener.java:43)
    at org.flowable.engine.impl.delegate.invocation.TaskListenerInvocation.invoke(TaskListenerInvocation.java:35)
    at org.flowable.engine.impl.delegate.invocation.DelegateInvocation.proceed(DelegateInvocation.java:35)
    at org.flowable.engine.impl.delegate.invocation.DefaultDelegateInterceptor.handleInvocation(DefaultDelegateInterceptor.java:26)
    at org.flowable.engine.impl.bpmn.helper.ClassDelegate.notify(ClassDelegate.java:125)

Did you prefix it with the package org.flowable.engine.impl.util ? So org.flowable.engine.impl.util.CommandContextUtil.

Also, if this doesn’t work, is there a reason for using Groovy? Setting a variable can also be done through an expression.

Thanks. I could access the execution now.
But the result stayed the same.

The variables were still set in the task context.

But finally, I managed to solve the problem. I had to look for the (root) process execution to get the correct execution context.

Here is the code. Notice that I query for the processInstance instead of the executionInstance:

def execution = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
execution.setVariables(task.getVariablesLocal());

Thank you very much for your help :slight_smile:

Ok, happy you found the solution :-).

It does look like something is between your tasks/executions, which isn’t there for the process instance. Would be good to check that, there might be subtle bugs arising potentially when one assumes variables to propagate (or maybe not, we don’t know your use case ofc).

Yeah, unfortunally, it is a third-party IDM software. So I cannot determine, what causes this behavior.

I can only see, that the variables created or changed in the usertask end up in the act_hi_varinst table with an execution_id_ different from the process_instance_id_ and both different from the task_id_.

As I query the workflows through the IDM rest interface, the error might also be in this part. Anyway, I’m very thankful for your help, because it pointed me in the right direction.