Hey guys.
I tried a couple of workarounds with CaseExecutionListeners today and are a bit puzzled how to achieve the following:
@Test
@Deployment(resources = "test.cmmn")
public void testRepeatingSentry() {
CaseService caseService = processEngine().getCaseService();
TaskService taskService = processEngine().getTaskService();
CaseInstance ci = caseService.createCaseInstanceByKey( //
"test", //
Variables.createVariables() //
.putValue("a", 5));
assertEquals(2, caseService.createCaseExecutionQuery().caseInstanceId(ci.getId()).activityId("HumanTask_Test").active().count() );
assertEquals(1, caseService.createCaseExecutionQuery().caseInstanceId(ci.getId()).activityId("HumanTask_Test").available().count() );
assertEquals(2, taskService.createTaskQuery().caseInstanceId(ci.getCaseInstanceId()).count() );
}
This is my CMMN Model: test.cmmn (4.4 KB)
I have the listener on the Human Task and want to trigger basically a second instance of the Human Task via setting a variable and using the VariableOnPart-Sentry. As the Human Task is repeatable, that should be possible (I thought).
But when I attach the listener to the event “start”, it seems not to trigger the VariableOnPart at all.
When I attach the listener to the event “create”, it does an endless loop, as it checks all incoming sentries (even the “normal” one which just fired) and creates the current task again - and again - and again… Easily to test with the test case I provided. Here the listener (hey - I cannot attach Java Code to the forum?):
public class MultipleInstanceTaskStartListener implements CaseExecutionListener {
@Override
public void notify(final DelegateCaseExecution ctx) throws Exception {
if (!ctx.hasVariable("elementTrigger")) {
// First element
ctx.setVariable(ctx.getActivityId() + "_started", true);
ctx.setVariable("elementTrigger", null);
Collection elements = (Collection) ctx.getVariable("elements");
Iterator iterator = elements.iterator();
Object firstElement = iterator.next();
ctx.setVariableLocal("element", firstElement);
iterator.forEachRemaining(new Consumer() {
public void accept(Object element) {
ctx.setVariable("elementTrigger", element);
}
});
} else {
// next elements
Object element = ctx.getVariable("elementTrigger");
ctx.setVariableLocal("element", element);
}
}
Understandable what I mean?
I wonder if this is somehow possible? Or what could be a good workaround to achieve what I want?
The real use case behind is a kind of “Multiple Instance” task which I have to create in parallel for every document in a list of documents. I need the first “Normal” sentry in order to avoid auto-completion and the VariuableOnPart to trigger a arbritrary amount of additional tasks later on.
I also thought about
- using a list as variable
- use this in the “normal” sentry if part
- add a “create” listener which checks the list, removes the first element (as this is currently started) and set the list
- this triggers a new evaluation and a second task
- until the list is empty.
HEre is the CMMN: MultipleInstance2.cmmn (3.0 KB), and the listener:
public class MultipleInstance2TaskCreateListener implements CaseExecutionListener {
@Override
public void notify(final DelegateCaseExecution ctx) throws Exception {
Collection elements = (Collection) ctx.getVariable("elements");
if (elements.iterator().hasNext()) {
Object firstElement = elements.iterator().next();
elements.remove(firstElement);
ctx.setVariableLocal("element", firstElement);
ctx.setVariable("elements", elements);
}
}
But this seems to change the case state itself - so it produces an exception:
Caused by: org.camunda.bpm.engine.exception.cmmn.CaseIllegalStateTransitionException: ENGINE-05010 Could not perform transition 'create on case execution with id '18'.Reason: The case execution is already in state 'available'.
at org.camunda.bpm.engine.impl.cmmn.behavior.CmmnBehaviorLogger.isAlreadyInStateException(CmmnBehaviorLogger.java:165)
at org.camunda.bpm.engine.impl.cmmn.behavior.PlanItemDefinitionActivityBehavior.ensureTransitionAllowed(PlanItemDefinitionActivityBehavior.java:226)
at org.camunda.bpm.engine.impl.cmmn.behavior.PlanItemDefinitionActivityBehavior.onCreate(PlanItemDefinitionActivityBehavior.java:90)
So I am a but puzzled which way WOULD be a possible to do this in plain CMMN. Any idea?
Cheers
Bernd