Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,13 @@ public void testSignal() {
assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero();

Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult();
assertThat(task).isNotNull();
assertThat(task.getTaskDefinitionKey()).isEqualTo("theTask");
assertThat(task.getName()).isEqualTo("my task");
assertThatCaseTaskWasCreated(task);

EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
assertThat(eventSubscription.getEventName()).isEqualTo("testSignal");
assertThatEventSubscriptionExists(caseInstance);

processEngineTaskService.complete(task.getId());

eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
assertThat(eventSubscription).isNull();

Task task2 = processEngineTaskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
Expand Down Expand Up @@ -94,22 +91,18 @@ public void testMultipleSignals() {
assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero();

Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult();
assertThat(task).isNotNull();
assertThat(task.getTaskDefinitionKey()).isEqualTo("theTask");
assertThat(task.getName()).isEqualTo("my task");
assertThatCaseTaskWasCreated(task);

EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
assertThat(eventSubscription.getEventName()).isEqualTo("testSignal");
assertThatEventSubscriptionExists(caseInstance);

EventSubscription anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult();
assertThat(anotherEventSubscription.getEventName()).isEqualTo("testSignal");
assertThatEventSubscriptionExists(anotherCaseInstance);

processEngineTaskService.complete(task.getId());

eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
assertThat(eventSubscription).isNull();

anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult();
EventSubscription anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult();
assertThat(anotherEventSubscription).isNull();

Task task2 = processEngineTaskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
Expand Down Expand Up @@ -152,16 +145,13 @@ public void testSignalWithInstanceScope() {
assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero();

Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult();
assertThat(task).isNotNull();
assertThat(task.getTaskDefinitionKey()).isEqualTo("theTask");
assertThat(task.getName()).isEqualTo("my task");
assertThatCaseTaskWasCreated(task);

EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
assertThat(eventSubscription.getEventName()).isEqualTo("testSignal");
assertThatEventSubscriptionExists(caseInstance);

processEngineTaskService.complete(task.getId());

eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
assertThat(eventSubscription).isNull();

Task task2 = processEngineTaskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
Expand Down Expand Up @@ -201,19 +191,17 @@ public void testMultipleSignalWithInstanceScope() {

assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero();

EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
assertThat(eventSubscription.getEventName()).isEqualTo("testSignal");
assertThatEventSubscriptionExists(caseInstance);

EventSubscription anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult();
assertThat(anotherEventSubscription.getEventName()).isEqualTo("testSignal");
assertThatEventSubscriptionExists(anotherCaseInstance);

Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance.getId()).singleResult();
processEngineTaskService.complete(task.getId());

eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
assertThat(eventSubscription).isNull();

anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult();
EventSubscription anotherEventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(anotherCaseInstance.getId()).singleResult();
assertThat(anotherEventSubscription.getEventName()).isEqualTo("testSignal");

Task task2 = processEngineTaskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
Expand Down Expand Up @@ -259,8 +247,7 @@ public void testTerminateCaseInstanceWithSignal() {

assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).count()).isZero();

EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance.getId()).singleResult();
assertThat(eventSubscription.getEventName()).isEqualTo("testSignal");
assertThatEventSubscriptionExists(caseInstance);

cmmnRuntimeService.terminateCaseInstance(caseInstance.getId());

Expand Down Expand Up @@ -301,4 +288,45 @@ public void testPassVariablesThroughCaseInstanceService() {

}

@Test
@CmmnDeployment(resources = { "org/flowable/cmmn/test/processTaskWithSignalListener.cmmn" })
public void multipleSignalSubscribers() {
Deployment deployment = this.processEngineRepositoryService.createDeployment().
addClasspathResource("org/flowable/cmmn/test/signalProcess.bpmn20.xml").
deploy();

try {
CaseInstance caseInstance1 = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("signalCase").start();
CaseInstance caseInstance2 = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("signalCase").start();

assertThat(cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance1.getId()).count()).isZero();
assertThat(cmmnRuntimeService.createEventSubscriptionQuery().count()).isEqualTo(2L);

Task task = processEngineTaskService.createTaskQuery().caseInstanceIdWithChildren(caseInstance1.getId()).singleResult();

assertThatCaseTaskWasCreated(task);
assertThatEventSubscriptionExists(caseInstance1);
assertThatEventSubscriptionExists(caseInstance2);

processEngineTaskService.complete(task.getId());

assertThat(cmmnRuntimeService.createEventSubscriptionQuery().count())
.as("The signal triggers 2 subscribers.")
.isZero();
} finally {
processEngine.getRepositoryService().deleteDeployment(deployment.getId(), true);
}
}

private void assertThatEventSubscriptionExists(CaseInstance caseInstance1) {
EventSubscription eventSubscription = cmmnRuntimeService.createEventSubscriptionQuery().scopeId(caseInstance1.getId()).singleResult();
assertThat(eventSubscription.getEventName()).isEqualTo("testSignal");
}

private static void assertThatCaseTaskWasCreated(Task task) {
assertThat(task).isNotNull();
assertThat(task.getTaskDefinitionKey()).isEqualTo("theTask");
assertThat(task.getName()).isEqualTo("my task");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@
import org.flowable.engine.impl.util.ProcessInstanceHelper;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.eventsubscription.service.impl.persistence.entity.EventSubscriptionEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Daniel Meyer
* @author Joram Barrez
*/
public class SignalEventHandler extends AbstractEventHandler {

public static final String EVENT_HANDLER_TYPE = "signal";

@Override
Expand All @@ -51,10 +52,6 @@ public void handleEvent(EventSubscriptionEntity eventSubscription, Object payloa
org.flowable.bpmn.model.Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
ProcessDefinition processDefinition = ProcessDefinitionUtil.getProcessDefinition(processDefinitionId);

if (processDefinition.isSuspended()) {
throw new FlowableException("Could not handle signal: process definition with id: " + processDefinitionId + " is suspended for " + eventSubscription);
}
Comment on lines -54 to -56
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still incorrect. If someone explicitly triggers a suspended definition we should fail.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The situation here is the same as for executions (processes). If process instance is suspended and signal is triggered for the suspended process instance, SignalEventHandler does not check whether process instance is suspended or not.
because

      and (
       (EVT.EXECUTION_ID_ is null) 
       or 
       (EVT.EXECUTION_ID_ is not null AND EXC.SUSPENSION_STATE_ = 1)
      )

and that's why SignalEventHandler does not expect suspended process instance to be provided here.

The contract is the same for definitions. Suspended definitions are not provided to SignalEventHandler


// Start process instance via the flow element linked to the event
FlowElement flowElement = process.getFlowElement(eventSubscription.getActivityId(), true);
if (flowElement == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,25 @@ public void testSignalUserTask() {
.isExactlyInstanceOf(FlowableException.class);
}

@Test
@Deployment(resources={"org/flowable/engine/test/bpmn/event/signal/SignalEventTest.testSignalStartEvent.bpmn20.xml"})
public void testDuplicatedSuspendedSignalStartEventFromProcess() {
repositoryService.suspendProcessDefinitionByKey("processWithSignalStart1");

// An example of behavior when there is no subscription to the signal.
runtimeService.signalEventReceived("nonExisting");

// Starting the process that fires the signal should start 2 process
// instances that are listening on that signal. The suspended one is not included.
runtimeService.startProcessInstanceByKey("processWithSignalThrow");

// Verify
assertThat(runtimeService.createProcessInstanceQuery().count()).isEqualTo(2);
assertThat(taskService.createTaskQuery().list()).extracting(Task::getName)
.containsExactlyInAnyOrder("Task in process B", "Task in process C");

}

@Test
public void testSignalStartEventFromProcess() {

Expand Down Expand Up @@ -805,12 +824,13 @@ public void testSignalStartEventWithSuspendedDefinition() {

repositoryService.suspendProcessDefinitionByKey("processWithSignalStart1");

assertThatThrownBy(() -> runtimeService.startProcessInstanceByKey("processWithSignalThrow"))
.as("Suspended process definition should fail")
.isExactlyInstanceOf(FlowableException.class);
runtimeService.startProcessInstanceByKey("processWithSignalThrow");

// Verify
assertThat(runtimeService.createProcessInstanceQuery().count()).isZero();
assertThat(runtimeService.createProcessInstanceQuery().list())
.as("Signal throw event is swallowed for suspended process")
.extracting(ProcessInstance::getProcessDefinitionKey)
.containsExactlyInAnyOrder("processWithSignalStart2","processWithSignalStart3");

repositoryService.activateProcessDefinitionByKey("processWithSignalStart1");

Expand All @@ -819,8 +839,8 @@ public void testSignalStartEventWithSuspendedDefinition() {
runtimeService.startProcessInstanceByKey("processWithSignalThrow");

// Verify
assertThat(runtimeService.createProcessInstanceQuery().count()).isEqualTo(3);
assertThat(taskService.createTaskQuery().count()).isEqualTo(3);
assertThat(runtimeService.createProcessInstanceQuery().count()).isEqualTo(5);
assertThat(taskService.createTaskQuery().count()).isEqualTo(5);

// Cleanup
cleanup();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,11 @@
where EVENT_TYPE_ = 'signal'
and EVENT_NAME_ = #{parameter.eventName, jdbcType=NVARCHAR}
and (
(EVT.EXECUTION_ID_ is null)
or
(EVT.EXECUTION_ID_ is not null AND EXC.SUSPENSION_STATE_ = 1)
(EVT.EXECUTION_ID_ is null and EVT.PROC_DEF_ID_ is not null and exists (select 1 from ACT_RE_PROCDEF DEF where DEF.ID_ = EVT.PROC_DEF_ID_ and DEF.SUSPENSION_STATE_ = 1))
or
(EVT.EXECUTION_ID_ is not null AND EXC.SUSPENSION_STATE_ = 1)
or
(EVT.SCOPE_TYPE_ is not null and EVT.SCOPE_ID_ is not null and EVT.SCOPE_DEFINITION_ID_ is not null and EVT.SUB_SCOPE_ID_ is not null)
)
<if test="parameter.tenantId != null">
and EVT.TENANT_ID_ = #{parameter.tenantId, jdbcType=NVARCHAR}
Expand Down