cancel
Showing results for 
Search instead for 
Did you mean: 

Behavior of variables in embedded subprocesses

meweiss
Champ in-the-making
Champ in-the-making
The documentation did not have any information on this, so I wanted to confirm what my experimental testing found:

1) If you have an embedded subprocesses, you don't need to re-define the variables in the start event of the subprocess. A sequence flow coming out of a gateway in an embedded subprocess can read the variable values defined in the parent.

2) If you have a naming conflict with a variable with the same ID but different default values in the parent start event and subprocess start event, activiti will use the value from the parent. I find this unintuitive, I would expect the embedded subprocess to pick up on the most "local" variable, aka the one in the subprocess start event.

See BPMN below which I tested with. In the gateway in the embedded subprocess, the variable evaluated to "true", which was the value set in the parent start event (false was the value set in the subprocess start event).

<?xml version="1.0" encoding="UTF-8"?>
<definitions expressionLanguage="http://www.w3.org/1999/XPath"
    id="definitions" targetNamespace="testSubProcessWithVarCategory"
    typeLanguage="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
    xmlns:activiti="http://activiti.org/bpmn"
    xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
    xmlnsSmiley Surprisedmgdc="http://www.omg.org/spec/DD/20100524/DC"
    xmlnsSmiley Surprisedmgdi="http://www.omg.org/spec/DD/20100524/DI"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <process id="subprocessvarscope" isExecutable="true" name="test sub process">
        <startEvent activiti:async="true" id="start" name="Start">
            <extensionElements>
                <activiti:formProperty default="true" id="task1Var1Id"
                    name="var1_name" required="true" type="boolean"/>
                <activiti:formProperty id="task1Var2Id" name="var2_name"
                    required="true" type="string"/>
            </extensionElements>
        </startEvent>
        <serviceTask activiti:async="true"
            activiti:class="com.google.partnerservices.symphony.core.SymphonyTaskDelegate"
            id="task1" name="task 1">
            <extensionElements>
                <activiti:field name="variableNames">
                    <activiti:string><![CDATA[task1Var1Id, task1Var2Id]]></activiti:string>
                </activiti:field>
            </extensionElements>
        </serviceTask>
        <subProcess id="subProcess1" name="subProcess">
            <startEvent activiti:async="true" id="subProcessStart" name="sub Process Start Event">
                <extensionElements>
                    <activiti:formProperty default="false"
                        id="task1Var1Id" name="var1_name"
                        required="true" type="boolean"/>
                </extensionElements>
            </startEvent>
            <serviceTask activiti:async="true"
                activiti:class="com.google.partnerservices.symphony.core.SymphonyTaskDelegate"
                id="task2" name="if var1 = true"/>
            <endEvent activiti:async="true" id="subProcessEnd" name="sub process end event"/>
            <sequenceFlow id="subProcessFlow1"
                sourceRef="subProcessStart" targetRef="exclusivegateway1"/>
            <sequenceFlow id="subProcessFlow2" sourceRef="task2" targetRef="subProcessEnd"/>
            <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"/>
            <sequenceFlow id="flow4" sourceRef="exclusivegateway1" targetRef="task2">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task1Var1Id == 'true'}]]></conditionExpression>
            </sequenceFlow>
            <serviceTask activiti:async="true"
                activiti:class="com.google.partnerservices.symphony.core.SymphonyTaskDelegate"
                id="servicetask1" name="Service Task"/>
            <sequenceFlow id="flow5" sourceRef="exclusivegateway1" targetRef="servicetask1">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${task1Var1Id == 'false'}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="flow6" sourceRef="servicetask1" targetRef="subProcessEnd"/>
        </subProcess>
        <endEvent id="end" name="End"/>
        <sequenceFlow id="flow1" sourceRef="start" targetRef="task1"/>
        <sequenceFlow id="flow2" sourceRef="task1" targetRef="subProcess1"/>
        <sequenceFlow id="flow3" sourceRef="subProcess1" targetRef="end"/>
    </process>
</definitions>

Any reason why this behavior was chosen, since it feels more unintuitive? Can this be added to the Activiti documentation?
2 REPLIES 2

jbarrez
Star Contributor
Star Contributor
1. Correct. Embedded subprocesses are a part of the process instance like any other activity. Call Activity is the only exception to that.

2. True. This is one of the shortcomings in v5 we're fixing in v6. In v6, there will be a 'subprocess scope' for variables and it will work as you describe (with the local variables)

But in this particular case, I would think the local variable did get chosen. It seems your example is missing from the post. Can you reupload it?

meweiss
Champ in-the-making
Champ in-the-making
Hrm, this BPMN just does not want to post… I tried yesterday and got stuck in an approval queue. Trying again, uploading as an attachment.