提交 0d0727d9 编写于 作者: M martin.grofcik

ACT-1822

MultiInstance loopIndexVariable support
上级 a2670ade
...@@ -133,7 +133,8 @@ public interface BpmnXMLConstants { ...@@ -133,7 +133,8 @@ public interface BpmnXMLConstants {
public static final String ATTRIBUTE_MULTIINSTANCE_SEQUENTIAL = "isSequential"; public static final String ATTRIBUTE_MULTIINSTANCE_SEQUENTIAL = "isSequential";
public static final String ATTRIBUTE_MULTIINSTANCE_COLLECTION = "collection"; public static final String ATTRIBUTE_MULTIINSTANCE_COLLECTION = "collection";
public static final String ATTRIBUTE_MULTIINSTANCE_VARIABLE = "elementVariable"; public static final String ATTRIBUTE_MULTIINSTANCE_VARIABLE = "elementVariable";
public static final String ATTRIBUTE_MULTIINSTANCE_INDEX_VARIABLE = "elementIndexVariable";
public static final String ATTRIBUTE_TASK_IMPLEMENTATION = "implementation"; public static final String ATTRIBUTE_TASK_IMPLEMENTATION = "implementation";
public static final String ATTRIBUTE_TASK_OPERATION_REF = "operationRef"; public static final String ATTRIBUTE_TASK_OPERATION_REF = "operationRef";
......
...@@ -39,6 +39,7 @@ public class MultiInstanceParser extends BaseChildElementParser { ...@@ -39,6 +39,7 @@ public class MultiInstanceParser extends BaseChildElementParser {
} }
multiInstanceDef.setInputDataItem(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_MULTIINSTANCE_COLLECTION)); multiInstanceDef.setInputDataItem(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_MULTIINSTANCE_COLLECTION));
multiInstanceDef.setElementVariable(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_MULTIINSTANCE_VARIABLE)); multiInstanceDef.setElementVariable(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_MULTIINSTANCE_VARIABLE));
multiInstanceDef.setElementIndexVariable(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_MULTIINSTANCE_INDEX_VARIABLE));
boolean readyWithMultiInstance = false; boolean readyWithMultiInstance = false;
try { try {
......
...@@ -21,6 +21,7 @@ public class MultiInstanceLoopCharacteristics extends BaseElement { ...@@ -21,6 +21,7 @@ public class MultiInstanceLoopCharacteristics extends BaseElement {
protected String loopCardinality; protected String loopCardinality;
protected String completionCondition; protected String completionCondition;
protected String elementVariable; protected String elementVariable;
protected String elementIndexVariable;
protected boolean sequential; protected boolean sequential;
public String getInputDataItem() { public String getInputDataItem() {
...@@ -47,6 +48,12 @@ public class MultiInstanceLoopCharacteristics extends BaseElement { ...@@ -47,6 +48,12 @@ public class MultiInstanceLoopCharacteristics extends BaseElement {
public void setElementVariable(String elementVariable) { public void setElementVariable(String elementVariable) {
this.elementVariable = elementVariable; this.elementVariable = elementVariable;
} }
public String getElementIndexVariable() {
return elementIndexVariable;
}
public void setElementIndexVariable(String elementIndexVariable) {
this.elementIndexVariable = elementIndexVariable;
}
public boolean isSequential() { public boolean isSequential() {
return sequential; return sequential;
} }
......
...@@ -60,9 +60,6 @@ public abstract class MultiInstanceActivityBehavior extends FlowNodeActivityBeha ...@@ -60,9 +60,6 @@ public abstract class MultiInstanceActivityBehavior extends FlowNodeActivityBeha
protected final String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances"; protected final String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances";
protected final String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances"; protected final String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances";
// Variable names for inner instances (as described in the spec)
protected final String LOOP_COUNTER = "loopCounter";
// Instance members // Instance members
protected ActivityImpl activity; protected ActivityImpl activity;
protected AbstractBpmnActivityBehavior innerActivityBehavior; protected AbstractBpmnActivityBehavior innerActivityBehavior;
...@@ -71,7 +68,9 @@ public abstract class MultiInstanceActivityBehavior extends FlowNodeActivityBeha ...@@ -71,7 +68,9 @@ public abstract class MultiInstanceActivityBehavior extends FlowNodeActivityBeha
protected Expression collectionExpression; protected Expression collectionExpression;
protected String collectionVariable; protected String collectionVariable;
protected String collectionElementVariable; protected String collectionElementVariable;
// default variable name for loop counter for inner instances (as described in the spec)
protected String collectionElementIndexVariable="loopCounter";
/** /**
* @param innerActivityBehavior The original {@link ActivityBehavior} of the activity * @param innerActivityBehavior The original {@link ActivityBehavior} of the activity
* that will be wrapped inside this behavior. * that will be wrapped inside this behavior.
...@@ -84,7 +83,7 @@ public abstract class MultiInstanceActivityBehavior extends FlowNodeActivityBeha ...@@ -84,7 +83,7 @@ public abstract class MultiInstanceActivityBehavior extends FlowNodeActivityBeha
} }
public void execute(ActivityExecution execution) throws Exception { public void execute(ActivityExecution execution) throws Exception {
if (getLocalLoopVariable(execution, LOOP_COUNTER) == null) { if (getLocalLoopVariable(execution, getCollectionElementIndexVariable()) == null) {
try { try {
createInstances(execution); createInstances(execution);
} catch (BpmnError error) { } catch (BpmnError error) {
...@@ -291,6 +290,12 @@ public abstract class MultiInstanceActivityBehavior extends FlowNodeActivityBeha ...@@ -291,6 +290,12 @@ public abstract class MultiInstanceActivityBehavior extends FlowNodeActivityBeha
public void setCollectionElementVariable(String collectionElementVariable) { public void setCollectionElementVariable(String collectionElementVariable) {
this.collectionElementVariable = collectionElementVariable; this.collectionElementVariable = collectionElementVariable;
} }
public String getCollectionElementIndexVariable() {
return collectionElementIndexVariable;
}
public void setCollectionElementIndexVariable(String collectionElementIndexVariable) {
this.collectionElementIndexVariable = collectionElementIndexVariable;
}
public void setInnerActivityBehavior(AbstractBpmnActivityBehavior innerActivityBehavior) { public void setInnerActivityBehavior(AbstractBpmnActivityBehavior innerActivityBehavior) {
this.innerActivityBehavior = innerActivityBehavior; this.innerActivityBehavior = innerActivityBehavior;
this.innerActivityBehavior.setMultiInstanceActivityBehavior(this); this.innerActivityBehavior.setMultiInstanceActivityBehavior(this);
......
...@@ -78,7 +78,7 @@ public class ParallelMultiInstanceBehavior extends MultiInstanceActivityBehavior ...@@ -78,7 +78,7 @@ public class ParallelMultiInstanceBehavior extends MultiInstanceActivityBehavior
if (concurrentExecution.isActive() && !concurrentExecution.isEnded() if (concurrentExecution.isActive() && !concurrentExecution.isEnded()
&& concurrentExecution.getParent().isActive() && concurrentExecution.getParent().isActive()
&& !concurrentExecution.getParent().isEnded()) { && !concurrentExecution.getParent().isEnded()) {
setLoopVariable(concurrentExecution, LOOP_COUNTER, loopCounter); setLoopVariable(concurrentExecution, getCollectionElementIndexVariable(), loopCounter);
executeOriginalBehavior(concurrentExecution, loopCounter); executeOriginalBehavior(concurrentExecution, loopCounter);
} }
} }
...@@ -101,7 +101,7 @@ public class ParallelMultiInstanceBehavior extends MultiInstanceActivityBehavior ...@@ -101,7 +101,7 @@ public class ParallelMultiInstanceBehavior extends MultiInstanceActivityBehavior
public void leave(ActivityExecution execution) { public void leave(ActivityExecution execution) {
callActivityEndListeners(execution); callActivityEndListeners(execution);
int loopCounter = getLoopVariable(execution, LOOP_COUNTER); int loopCounter = getLoopVariable(execution, getCollectionElementIndexVariable());
int nrOfInstances = getLoopVariable(execution, NUMBER_OF_INSTANCES); int nrOfInstances = getLoopVariable(execution, NUMBER_OF_INSTANCES);
int nrOfCompletedInstances = getLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES) + 1; int nrOfCompletedInstances = getLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES) + 1;
int nrOfActiveInstances = getLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES) - 1; int nrOfActiveInstances = getLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES) - 1;
......
...@@ -43,7 +43,7 @@ public class SequentialMultiInstanceBehavior extends MultiInstanceActivityBehavi ...@@ -43,7 +43,7 @@ public class SequentialMultiInstanceBehavior extends MultiInstanceActivityBehavi
setLoopVariable(execution, NUMBER_OF_INSTANCES, nrOfInstances); setLoopVariable(execution, NUMBER_OF_INSTANCES, nrOfInstances);
setLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES, 0); setLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES, 0);
setLoopVariable(execution, LOOP_COUNTER, 0); setLoopVariable(execution, getCollectionElementIndexVariable(), 0);
setLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES, 1); setLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES, 1);
logLoopDetails(execution, "initialized", 0, 0, 1, nrOfInstances); logLoopDetails(execution, "initialized", 0, 0, 1, nrOfInstances);
...@@ -58,12 +58,12 @@ public class SequentialMultiInstanceBehavior extends MultiInstanceActivityBehavi ...@@ -58,12 +58,12 @@ public class SequentialMultiInstanceBehavior extends MultiInstanceActivityBehavi
public void leave(ActivityExecution execution) { public void leave(ActivityExecution execution) {
callActivityEndListeners(execution); callActivityEndListeners(execution);
int loopCounter = getLoopVariable(execution, LOOP_COUNTER) + 1; int loopCounter = getLoopVariable(execution, getCollectionElementIndexVariable()) + 1;
int nrOfInstances = getLoopVariable(execution, NUMBER_OF_INSTANCES); int nrOfInstances = getLoopVariable(execution, NUMBER_OF_INSTANCES);
int nrOfCompletedInstances = getLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES) + 1; int nrOfCompletedInstances = getLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES) + 1;
int nrOfActiveInstances = getLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES); int nrOfActiveInstances = getLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES);
setLoopVariable(execution, LOOP_COUNTER, loopCounter); setLoopVariable(execution, getCollectionElementIndexVariable(), loopCounter);
setLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES, nrOfCompletedInstances); setLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES, nrOfCompletedInstances);
logLoopDetails(execution, "instance completed", loopCounter, nrOfCompletedInstances, nrOfActiveInstances, nrOfInstances); logLoopDetails(execution, "instance completed", loopCounter, nrOfCompletedInstances, nrOfActiveInstances, nrOfInstances);
......
...@@ -91,6 +91,11 @@ public abstract class AbstractActivityBpmnParseHandler<T extends FlowNode> exten ...@@ -91,6 +91,11 @@ public abstract class AbstractActivityBpmnParseHandler<T extends FlowNode> exten
miActivityBehavior.setCollectionElementVariable(loopCharacteristics.getElementVariable()); miActivityBehavior.setCollectionElementVariable(loopCharacteristics.getElementVariable());
} }
// activiti:elementIndexVariable
if (StringUtils.isNotEmpty(loopCharacteristics.getElementIndexVariable())) {
miActivityBehavior.setCollectionElementIndexVariable(loopCharacteristics.getElementIndexVariable());
}
// Validation // Validation
if (miActivityBehavior.getLoopCardinalityExpression() == null && miActivityBehavior.getCollectionExpression() == null if (miActivityBehavior.getLoopCardinalityExpression() == null && miActivityBehavior.getCollectionExpression() == null
&& miActivityBehavior.getCollectionVariable() == null) { && miActivityBehavior.getCollectionVariable() == null) {
......
...@@ -43,28 +43,37 @@ public class MultiInstanceTest extends PluggableActivitiTestCase { ...@@ -43,28 +43,37 @@ public class MultiInstanceTest extends PluggableActivitiTestCase {
@Deployment(resources = {"org/activiti/engine/test/bpmn/multiinstance/MultiInstanceTest.sequentialUserTasks.bpmn20.xml"}) @Deployment(resources = {"org/activiti/engine/test/bpmn/multiinstance/MultiInstanceTest.sequentialUserTasks.bpmn20.xml"})
public void testSequentialUserTasks() { public void testSequentialUserTasks() {
String procId = runtimeService.startProcessInstanceByKey("miSequentialUserTasks", checkSequentialUserTasks("miSequentialUserTasks");
}
@Deployment
public void testSequentialUserTasksCustomExtensions() {
checkSequentialUserTasks("miSequentialUserTasksCustomExtensions");
}
private void checkSequentialUserTasks(String processDefinitionKey) {
String procId = runtimeService.startProcessInstanceByKey(processDefinitionKey,
CollectionUtil.singletonMap("nrOfLoops", 3)).getId(); CollectionUtil.singletonMap("nrOfLoops", 3)).getId();
Task task = taskService.createTaskQuery().singleResult(); Task task = taskService.createTaskQuery().singleResult();
assertEquals("My Task", task.getName()); assertEquals("My Task", task.getName());
assertEquals("kermit_0", task.getAssignee()); assertEquals("kermit_0", task.getAssignee());
taskService.complete(task.getId()); taskService.complete(task.getId());
task = taskService.createTaskQuery().singleResult(); task = taskService.createTaskQuery().singleResult();
assertEquals("My Task", task.getName()); assertEquals("My Task", task.getName());
assertEquals("kermit_1", task.getAssignee()); assertEquals("kermit_1", task.getAssignee());
taskService.complete(task.getId()); taskService.complete(task.getId());
task = taskService.createTaskQuery().singleResult(); task = taskService.createTaskQuery().singleResult();
assertEquals("My Task", task.getName()); assertEquals("My Task", task.getName());
assertEquals("kermit_2", task.getAssignee()); assertEquals("kermit_2", task.getAssignee());
taskService.complete(task.getId()); taskService.complete(task.getId());
assertNull(taskService.createTaskQuery().singleResult()); assertNull(taskService.createTaskQuery().singleResult());
assertProcessEnded(procId); assertProcessEnded(procId);
} }
@Deployment(resources = {"org/activiti/engine/test/bpmn/multiinstance/MultiInstanceTest.sequentialUserTasks.bpmn20.xml"}) @Deployment(resources = {"org/activiti/engine/test/bpmn/multiinstance/MultiInstanceTest.sequentialUserTasks.bpmn20.xml"})
public void testSequentialUserTasksHistory() { public void testSequentialUserTasksHistory() {
runtimeService.startProcessInstanceByKey("miSequentialUserTasks", runtimeService.startProcessInstanceByKey("miSequentialUserTasks",
...@@ -240,18 +249,39 @@ public class MultiInstanceTest extends PluggableActivitiTestCase { ...@@ -240,18 +249,39 @@ public class MultiInstanceTest extends PluggableActivitiTestCase {
@Deployment @Deployment
public void testParallelUserTasksCustomExtensions() { public void testParallelUserTasksCustomExtensions() {
checkParallelUserTasksCustomExtensions("miParallelUserTasks");
}
@Deployment
public void testParallelUserTasksCustomExtensionsLoopIndexVariable() {
checkParallelUserTasksCustomExtensions("miParallelUserTasksLoopVariable");
}
private void checkParallelUserTasksCustomExtensions(String processDefinitionKey) {
Map<String, Object> vars = new HashMap<String, Object>(); Map<String, Object> vars = new HashMap<String, Object>();
List<String> assigneeList = Arrays.asList("kermit", "gonzo", "fozzie"); List<String> assigneeList = Arrays.asList("kermit", "gonzo", "fozzie");
vars.put("assigneeList", assigneeList); vars.put("assigneeList", assigneeList);
runtimeService.startProcessInstanceByKey("miSequentialUserTasks", vars); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, vars);
for (String assignee : assigneeList) { List<Task> tasks = taskService.createTaskQuery().orderByTaskName().asc().list();
Task task = taskService.createTaskQuery().singleResult(); assertEquals(3, tasks.size());
assertEquals(assignee, task.getAssignee()); assertEquals("My Task 0", tasks.get(0).getName());
taskService.complete(task.getId()); assertEquals("My Task 1", tasks.get(1).getName());
} assertEquals("My Task 2", tasks.get(2).getName());
tasks = taskService.createTaskQuery().orderByTaskAssignee().asc().list();
assertEquals("fozzie", tasks.get(0).getAssignee());
assertEquals("gonzo", tasks.get(1).getAssignee());
assertEquals("kermit", tasks.get(2).getAssignee());
// Completing 3 tasks will trigger completioncondition
taskService.complete(tasks.get(0).getId());
taskService.complete(tasks.get(1).getId());
taskService.complete(tasks.get(2).getId());
assertEquals(0, taskService.createTaskQuery().count());
assertProcessEnded(processInstance.getProcessInstanceId());
} }
@Deployment @Deployment
public void testParallelUserTasksExecutionAndTaskListeners() { public void testParallelUserTasksExecutionAndTaskListeners() {
runtimeService.startProcessInstanceByKey("miParallelUserTasks"); runtimeService.startProcessInstanceByKey("miParallelUserTasks");
......
...@@ -5,13 +5,13 @@ ...@@ -5,13 +5,13 @@
xmlns:activiti="http://activiti.org/bpmn" xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="Examples"> targetNamespace="Examples">
<process id="miSequentialUserTasks"> <process id="miParallelUserTasks">
<startEvent id="theStart" /> <startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="miTasks" /> <sequenceFlow id="flow1" sourceRef="theStart" targetRef="miTasks" />
<userTask id="miTasks" name="My Task ${loopCounter}" activiti:assignee="${assignee}"> <userTask id="miTasks" name="My Task ${loopCounter}" activiti:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="true" <multiInstanceLoopCharacteristics isSequential="false"
activiti:collection="assigneeList" activiti:elementVariable="assignee"> activiti:collection="assigneeList" activiti:elementVariable="assignee">
</multiInstanceLoopCharacteristics> </multiInstanceLoopCharacteristics>
</userTask> </userTask>
......
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definition"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="Examples">
<process id="miParallelUserTasksLoopVariable">
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="miTasks" />
<userTask id="miTasks" name="My Task ${loopValueIndex}" activiti:assignee="${assignee}" >
<multiInstanceLoopCharacteristics isSequential="false"
activiti:collection="assigneeList" activiti:elementVariable="assignee"
activiti:elementIndexVariable="loopValueIndex"/>
</userTask>
<sequenceFlow id="flow3" sourceRef="miTasks" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definition"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="Examples">
<process id="miSequentialUserTasksCustomExtensions">
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="miTasks" />
<userTask id="miTasks" name="My Task" activiti:assignee="kermit_${loopValueIndex}">
<multiInstanceLoopCharacteristics isSequential="true" activiti:elementIndexVariable="loopValueIndex">
<loopCardinality>${nrOfLoops}</loopCardinality>
<completionCondition>${nrOfCompletedInstances == 5}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
<sequenceFlow id="flow4" sourceRef="miTasks" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
\ No newline at end of file
...@@ -4835,7 +4835,8 @@ public class MyTaskCreateListener implements TaskListener { ...@@ -4835,7 +4835,8 @@ public class MyTaskCreateListener implements TaskListener {
Additionally, each of the created executions will have an execution-local variable (i.e. not visible Additionally, each of the created executions will have an execution-local variable (i.e. not visible
for the other executions, and not stored on process instance level) : for the other executions, and not stored on process instance level) :
<itemizedlist> <itemizedlist>
<listitem><para><emphasis role="bold">loopCounter</emphasis>: indicates the <emphasis>index in the for-each loop</emphasis> of that particular instance.</para></listitem> <listitem><para><emphasis role="bold">loopCounter</emphasis>: indicates the <emphasis>index in the for-each loop</emphasis> of that particular instance. loopCounter variable can be renamed by activiti
<emphasis role="bold">elementIndexVariable</emphasis> attribute.</para></listitem>
</itemizedlist> </itemizedlist>
</para> </para>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册