Skip to content

Commit da9faf3

Browse files
committed
Move event-sub-process start subscription registration onto the StartEvent behavior
Each event-sub-process StartEvent ActivityBehavior now owns its full lifecycle via a new EventSubProcessStartEventActivityBehavior interface (initializeEventSubProcessStart(context)). The five built-in subscription registering behaviors (Message, Signal, Timer, EventRegistry, VariableListener) absorb the bodies of the corresponding handle... helpers from ProcessInstanceHelper, which collapses to a single delegated call. The context exposes createEventScopeChildExecution(), createEventSubscriptionBuilder(execution), and record callbacks that preserve the two-pass message/signal-waiting dispatch.
1 parent d3b8fe3 commit da9faf3

9 files changed

Lines changed: 283 additions & 203 deletions

modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/EventSubProcessEventRegistryStartEventActivityBehavior.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@
2020
import java.util.Map;
2121
import java.util.Objects;
2222

23+
import org.apache.commons.lang3.StringUtils;
24+
import org.flowable.bpmn.constants.BpmnXMLConstants;
2325
import org.flowable.bpmn.model.EventSubProcess;
2426
import org.flowable.bpmn.model.StartEvent;
2527
import org.flowable.bpmn.model.SubProcess;
2628
import org.flowable.bpmn.model.ValuedDataObject;
29+
import org.flowable.common.engine.api.scope.ScopeTypes;
2730
import org.flowable.common.engine.impl.context.Context;
2831
import org.flowable.common.engine.impl.interceptor.CommandContext;
2932
import org.flowable.engine.delegate.DelegateExecution;
@@ -34,6 +37,7 @@
3437
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
3538
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
3639
import org.flowable.engine.impl.util.CommandContextUtil;
40+
import org.flowable.engine.impl.util.CorrelationUtil;
3741
import org.flowable.engine.impl.util.CountingEntityUtil;
3842
import org.flowable.eventregistry.api.runtime.EventInstance;
3943
import org.flowable.eventregistry.impl.constant.EventConstants;
@@ -45,7 +49,7 @@
4549
*
4650
* @author Tijs Rademakers
4751
*/
48-
public class EventSubProcessEventRegistryStartEventActivityBehavior extends AbstractBpmnActivityBehavior {
52+
public class EventSubProcessEventRegistryStartEventActivityBehavior extends AbstractBpmnActivityBehavior implements EventSubProcessStartEventActivityBehavior {
4953

5054
private static final long serialVersionUID = 1L;
5155

@@ -55,6 +59,23 @@ public EventSubProcessEventRegistryStartEventActivityBehavior(String eventDefini
5559
this.eventDefinitionKey = eventDefinitionKey;
5660
}
5761

62+
@Override
63+
public void initializeEventSubProcessStart(EventSubProcessStartEventInitializerContext context) {
64+
if (StringUtils.isEmpty(eventDefinitionKey)) {
65+
return;
66+
}
67+
68+
ExecutionEntity eventRegistryExecution = context.createEventScopeChildExecution();
69+
70+
EventSubscriptionEntity eventSubscription = (EventSubscriptionEntity) context.createEventSubscriptionBuilder(eventRegistryExecution)
71+
.eventType(eventDefinitionKey)
72+
.scopeType(ScopeTypes.BPMN)
73+
.configuration(CorrelationUtil.getCorrelationKey(BpmnXMLConstants.ELEMENT_EVENT_CORRELATION_PARAMETER, context.getCommandContext(), eventRegistryExecution))
74+
.create();
75+
76+
CountingEntityUtil.handleInsertEventSubscriptionEntityCount(eventSubscription);
77+
}
78+
5879
@Override
5980
public void execute(DelegateExecution execution) {
6081
StartEvent startEvent = (StartEvent) execution.getCurrentFlowElement();

modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/EventSubProcessMessageStartEventActivityBehavior.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.List;
2020
import java.util.Map;
2121

22+
import org.flowable.bpmn.model.BpmnModel;
2223
import org.flowable.bpmn.model.EventSubProcess;
2324
import org.flowable.bpmn.model.MessageEventDefinition;
2425
import org.flowable.bpmn.model.StartEvent;
@@ -35,6 +36,7 @@
3536
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
3637
import org.flowable.engine.impl.util.CommandContextUtil;
3738
import org.flowable.engine.impl.util.CountingEntityUtil;
39+
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
3840
import org.flowable.eventsubscription.service.EventSubscriptionService;
3941
import org.flowable.eventsubscription.service.impl.persistence.entity.EventSubscriptionEntity;
4042
import org.flowable.eventsubscription.service.impl.persistence.entity.MessageEventSubscriptionEntity;
@@ -44,7 +46,7 @@
4446
*
4547
* @author Tijs Rademakers
4648
*/
47-
public class EventSubProcessMessageStartEventActivityBehavior extends AbstractBpmnActivityBehavior {
49+
public class EventSubProcessMessageStartEventActivityBehavior extends AbstractBpmnActivityBehavior implements EventSubProcessStartEventActivityBehavior {
4850

4951
private static final long serialVersionUID = 1L;
5052

@@ -54,6 +56,27 @@ public EventSubProcessMessageStartEventActivityBehavior(MessageEventDefinition m
5456
this.messageEventDefinition = messageEventDefinition;
5557
}
5658

59+
@Override
60+
public void initializeEventSubProcessStart(EventSubProcessStartEventInitializerContext context) {
61+
ExecutionEntity parentExecution = context.getParentExecution();
62+
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(parentExecution.getProcessDefinitionId());
63+
if (bpmnModel.containsMessageId(messageEventDefinition.getMessageRef())) {
64+
messageEventDefinition.setMessageRef(bpmnModel.getMessage(messageEventDefinition.getMessageRef()).getName());
65+
}
66+
67+
ExecutionEntity messageExecution = context.createEventScopeChildExecution();
68+
69+
String messageName = EventDefinitionExpressionUtil.determineMessageName(context.getCommandContext(), messageEventDefinition, parentExecution);
70+
EventSubscriptionEntity eventSubscription = (EventSubscriptionEntity) context.createEventSubscriptionBuilder(messageExecution)
71+
.eventType(MessageEventSubscriptionEntity.EVENT_TYPE)
72+
.eventName(messageName)
73+
.create();
74+
75+
CountingEntityUtil.handleInsertEventSubscriptionEntityCount(eventSubscription);
76+
context.recordWaitingMessageSubscription(eventSubscription);
77+
messageExecution.getEventSubscriptions().add(eventSubscription);
78+
}
79+
5780
@Override
5881
public void execute(DelegateExecution execution) {
5982
StartEvent startEvent = (StartEvent) execution.getCurrentFlowElement();

modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/EventSubProcessSignalStartEventActivityBehavior.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919
import java.util.List;
2020
import java.util.Map;
2121

22+
import org.flowable.bpmn.model.BpmnModel;
2223
import org.flowable.bpmn.model.EventSubProcess;
2324
import org.flowable.bpmn.model.Signal;
2425
import org.flowable.bpmn.model.SignalEventDefinition;
2526
import org.flowable.bpmn.model.StartEvent;
2627
import org.flowable.bpmn.model.SubProcess;
2728
import org.flowable.bpmn.model.ValuedDataObject;
29+
import org.flowable.common.engine.api.scope.ScopeTypes;
2830
import org.flowable.common.engine.impl.context.Context;
31+
import org.flowable.common.engine.impl.el.DefinitionVariableContainer;
2932
import org.flowable.common.engine.impl.interceptor.CommandContext;
3033
import org.flowable.engine.delegate.DelegateExecution;
3134
import org.flowable.engine.delegate.ExecutionListener;
@@ -46,7 +49,7 @@
4649
*
4750
* @author Tijs Rademakers
4851
*/
49-
public class EventSubProcessSignalStartEventActivityBehavior extends AbstractBpmnActivityBehavior {
52+
public class EventSubProcessSignalStartEventActivityBehavior extends AbstractBpmnActivityBehavior implements EventSubProcessStartEventActivityBehavior {
5053

5154
private static final long serialVersionUID = 1L;
5255

@@ -58,6 +61,31 @@ public EventSubProcessSignalStartEventActivityBehavior(SignalEventDefinition sig
5861
this.signal = signal;
5962
}
6063

64+
@Override
65+
public void initializeEventSubProcessStart(EventSubProcessStartEventInitializerContext context) {
66+
ExecutionEntity parentExecution = context.getParentExecution();
67+
if (signal != null) {
68+
signalEventDefinition.setSignalRef(signal.getName());
69+
}
70+
71+
ExecutionEntity signalExecution = context.createEventScopeChildExecution();
72+
73+
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(parentExecution.getProcessDefinitionId());
74+
DefinitionVariableContainer definitionVariableContainer = new DefinitionVariableContainer(parentExecution.getProcessDefinitionId(),
75+
parentExecution.getProcessDefinitionKey(), parentExecution.getDeploymentId(), ScopeTypes.BPMN, parentExecution.getTenantId());
76+
String eventName = EventDefinitionExpressionUtil.determineSignalName(context.getCommandContext(), signalEventDefinition, bpmnModel, definitionVariableContainer);
77+
78+
EventSubscriptionEntity eventSubscription = (EventSubscriptionEntity) context.createEventSubscriptionBuilder(signalExecution)
79+
.eventType(SignalEventSubscriptionEntity.EVENT_TYPE)
80+
.eventName(eventName)
81+
.signal(signal)
82+
.create();
83+
84+
CountingEntityUtil.handleInsertEventSubscriptionEntityCount(eventSubscription);
85+
context.recordWaitingSignalSubscription(eventSubscription);
86+
signalExecution.getEventSubscriptions().add(eventSubscription);
87+
}
88+
6189
@Override
6290
public void execute(DelegateExecution execution) {
6391
StartEvent startEvent = (StartEvent) execution.getCurrentFlowElement();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Licensed under the Apache License, Version 2.0 (the "License");
2+
* you may not use this file except in compliance with the License.
3+
* You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
package org.flowable.engine.impl.bpmn.behavior;
14+
15+
/**
16+
* Implemented by an {@code ActivityBehavior} attached to an event-sub-process {@code StartEvent} that
17+
* registers a subscription, timer or waiting execution when the parent process or sub-process becomes
18+
* active. The {@code execute()} / {@code trigger()} half of the lifecycle continues to live on the
19+
* existing {@code ActivityBehavior} interface; this interface adds the "register at parent start"
20+
* half so each behavior owns its full lifecycle.
21+
* <p>
22+
* Custom integrations that supply their own {@code EventDefinition} + parse handler + behavior opt
23+
* into event-sub-process subscription registration by implementing this interface — no change in
24+
* {@code ProcessInstanceHelper} is required.
25+
*/
26+
public interface EventSubProcessStartEventActivityBehavior {
27+
28+
void initializeEventSubProcessStart(EventSubProcessStartEventInitializerContext context);
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/* Licensed under the Apache License, Version 2.0 (the "License");
2+
* you may not use this file except in compliance with the License.
3+
* You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
package org.flowable.engine.impl.bpmn.behavior;
14+
15+
import java.util.List;
16+
17+
import org.flowable.bpmn.model.StartEvent;
18+
import org.flowable.common.engine.impl.interceptor.CommandContext;
19+
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
20+
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
21+
import org.flowable.eventsubscription.api.EventSubscriptionBuilder;
22+
import org.flowable.eventsubscription.service.impl.persistence.entity.EventSubscriptionEntity;
23+
24+
/**
25+
* Context passed to {@link EventSubProcessStartEventActivityBehavior#initializeEventSubProcessStart}
26+
* when a parent process or sub-process becomes active and its event-sub-process start events need
27+
* to register their subscriptions / timers / waiting executions.
28+
*/
29+
public class EventSubProcessStartEventInitializerContext {
30+
31+
protected final ExecutionEntity parentExecution;
32+
protected final StartEvent startEvent;
33+
protected final ProcessEngineConfigurationImpl processEngineConfiguration;
34+
protected final CommandContext commandContext;
35+
protected final List<EventSubscriptionEntity> messageEventSubscriptions;
36+
protected final List<EventSubscriptionEntity> signalEventSubscriptions;
37+
38+
public EventSubProcessStartEventInitializerContext(ExecutionEntity parentExecution, StartEvent startEvent,
39+
ProcessEngineConfigurationImpl processEngineConfiguration, CommandContext commandContext,
40+
List<EventSubscriptionEntity> messageEventSubscriptions, List<EventSubscriptionEntity> signalEventSubscriptions) {
41+
this.parentExecution = parentExecution;
42+
this.startEvent = startEvent;
43+
this.processEngineConfiguration = processEngineConfiguration;
44+
this.commandContext = commandContext;
45+
this.messageEventSubscriptions = messageEventSubscriptions;
46+
this.signalEventSubscriptions = signalEventSubscriptions;
47+
}
48+
49+
public ExecutionEntity getParentExecution() {
50+
return parentExecution;
51+
}
52+
53+
public StartEvent getStartEvent() {
54+
return startEvent;
55+
}
56+
57+
public ProcessEngineConfigurationImpl getProcessEngineConfiguration() {
58+
return processEngineConfiguration;
59+
}
60+
61+
public CommandContext getCommandContext() {
62+
return commandContext;
63+
}
64+
65+
/**
66+
* Returns an {@link EventSubscriptionBuilder} pre-filled with the execution / process-instance /
67+
* activity / process-definition / tenant ids of the supplied event-scope execution. Subscription-
68+
* registering initializers chain on it with the type-specific fields (eventType, eventName, etc.)
69+
* before calling {@code create()}.
70+
*/
71+
public EventSubscriptionBuilder createEventSubscriptionBuilder(ExecutionEntity eventScopeExecution) {
72+
return processEngineConfiguration.getEventSubscriptionServiceConfiguration().getEventSubscriptionService()
73+
.createEventSubscriptionBuilder()
74+
.executionId(eventScopeExecution.getId())
75+
.processInstanceId(eventScopeExecution.getProcessInstanceId())
76+
.activityId(eventScopeExecution.getCurrentActivityId())
77+
.processDefinitionId(eventScopeExecution.getProcessDefinitionId())
78+
.tenantId(eventScopeExecution.getTenantId());
79+
}
80+
81+
/**
82+
* Creates a child execution of the parent that represents the waiting state for this event-sub-process
83+
* start event: pointed at the start event, marked as event scope, and inactive. This is the four-line
84+
* pattern repeated by every built-in event-sub-process start initializer.
85+
*/
86+
public ExecutionEntity createEventScopeChildExecution() {
87+
ExecutionEntity execution = processEngineConfiguration.getExecutionEntityManager().createChildExecution(parentExecution);
88+
execution.setCurrentFlowElement(startEvent);
89+
execution.setEventScope(true);
90+
execution.setActive(false);
91+
return execution;
92+
}
93+
94+
/**
95+
* Records a message event subscription so that {@code processEventSubProcess} can dispatch
96+
* {@code ACTIVITY_MESSAGE_WAITING} for it after every start event in the same sub-process has
97+
* registered. No-op if the caller didn't supply a collection (e.g. dynamic state migration paths).
98+
*/
99+
public void recordWaitingMessageSubscription(EventSubscriptionEntity subscription) {
100+
if (messageEventSubscriptions != null) {
101+
messageEventSubscriptions.add(subscription);
102+
}
103+
}
104+
105+
/**
106+
* Records a signal event subscription so that {@code processEventSubProcess} can dispatch
107+
* {@code ACTIVITY_SIGNAL_WAITING} for it after every start event in the same sub-process has
108+
* registered. No-op if the caller didn't supply a collection (e.g. dynamic state migration paths).
109+
*/
110+
public void recordWaitingSignalSubscription(EventSubscriptionEntity subscription) {
111+
if (signalEventSubscriptions != null) {
112+
signalEventSubscriptions.add(subscription);
113+
}
114+
}
115+
}

modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/EventSubProcessTimerStartEventActivityBehavior.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,20 @@
2929
import org.flowable.engine.delegate.DelegateExecution;
3030
import org.flowable.engine.delegate.ExecutionListener;
3131
import org.flowable.engine.history.DeleteReason;
32+
import org.flowable.engine.impl.jobexecutor.TimerEventHandler;
33+
import org.flowable.engine.impl.jobexecutor.TriggerTimerEventJobHandler;
3234
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
3335
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
3436
import org.flowable.engine.impl.util.CommandContextUtil;
37+
import org.flowable.engine.impl.util.TimerUtil;
38+
import org.flowable.job.service.impl.persistence.entity.TimerJobEntity;
3539

3640
/**
3741
* Implementation of the BPMN 2.0 event subprocess timer start event.
3842
*
3943
* @author Tijs Rademakers
4044
*/
41-
public class EventSubProcessTimerStartEventActivityBehavior extends AbstractBpmnActivityBehavior {
45+
public class EventSubProcessTimerStartEventActivityBehavior extends AbstractBpmnActivityBehavior implements EventSubProcessStartEventActivityBehavior {
4246

4347
private static final long serialVersionUID = 1L;
4448

@@ -48,6 +52,18 @@ public EventSubProcessTimerStartEventActivityBehavior(TimerEventDefinition timer
4852
this.timerEventDefinition = timerEventDefinition;
4953
}
5054

55+
@Override
56+
public void initializeEventSubProcessStart(EventSubProcessStartEventInitializerContext context) {
57+
StartEvent startEvent = context.getStartEvent();
58+
ExecutionEntity timerExecution = context.createEventScopeChildExecution();
59+
60+
TimerJobEntity timerJob = TimerUtil.createTimerEntityForTimerEventDefinition(timerEventDefinition, startEvent,
61+
false, timerExecution, TriggerTimerEventJobHandler.TYPE, TimerEventHandler.createConfiguration(startEvent.getId(),
62+
timerEventDefinition.getEndDate(), timerEventDefinition.getCalendarName()));
63+
64+
context.getProcessEngineConfiguration().getJobServiceConfiguration().getTimerJobService().scheduleTimerJob(timerJob);
65+
}
66+
5167
@Override
5268
public void execute(DelegateExecution execution) {
5369
StartEvent startEvent = (StartEvent) execution.getCurrentFlowElement();

0 commit comments

Comments
 (0)