Skip to content

Commit 93c1f75

Browse files
added case and process end interceptor (#4116)
* added case and process end interceptor * polish and added afterEnd methods for both interceptors. also added terminate flag that is used to determine if a process/case ended or terminated. * wrapped the interceptor in one place * changed booelan terminated flag to string state
1 parent 918253c commit 93c1f75

File tree

11 files changed

+269
-1
lines changed

11 files changed

+269
-1
lines changed

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/CmmnEngineConfiguration.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@
198198
import org.flowable.cmmn.engine.interceptor.CreateCasePageTaskInterceptor;
199199
import org.flowable.cmmn.engine.interceptor.CreateCmmnExternalWorkerJobInterceptor;
200200
import org.flowable.cmmn.engine.interceptor.CreateHumanTaskInterceptor;
201+
import org.flowable.cmmn.engine.interceptor.EndCaseInstanceInterceptor;
201202
import org.flowable.cmmn.engine.interceptor.HumanTaskStateInterceptor;
202203
import org.flowable.cmmn.engine.interceptor.StartCaseInstanceInterceptor;
203204
import org.flowable.cmmn.image.CaseDiagramGenerator;
@@ -388,6 +389,8 @@ public class CmmnEngineConfiguration extends AbstractBuildableEngineConfiguratio
388389
protected List<CaseInstanceLifecycleListener> caseInstanceLifecycleListeners;
389390
protected Map<String, List<PlanItemInstanceLifecycleListener>> planItemInstanceLifecycleListeners;
390391
protected StartCaseInstanceInterceptor startCaseInstanceInterceptor;
392+
protected EndCaseInstanceInterceptor endCaseInstanceInterceptor;
393+
391394
protected CreateHumanTaskInterceptor createHumanTaskInterceptor;
392395
protected HumanTaskStateInterceptor humanTaskStateInterceptor;
393396
protected CreateCasePageTaskInterceptor createCasePageTaskInterceptor;
@@ -2501,6 +2504,14 @@ public CmmnEngineConfiguration setStartCaseInstanceInterceptor(StartCaseInstance
25012504
this.startCaseInstanceInterceptor = startCaseInstanceInterceptor;
25022505
return this;
25032506
}
2507+
2508+
public EndCaseInstanceInterceptor getEndCaseInstanceInterceptor() {
2509+
return endCaseInstanceInterceptor;
2510+
}
2511+
2512+
public void setEndCaseInstanceInterceptor(EndCaseInstanceInterceptor endCaseInstanceInterceptor) {
2513+
this.endCaseInstanceInterceptor = endCaseInstanceInterceptor;
2514+
}
25042515

25052516
public CreateHumanTaskInterceptor getCreateHumanTaskInterceptor() {
25062517
return createHumanTaskInterceptor;

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/AbstractDeleteCaseInstanceOperation.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,14 @@ public AbstractDeleteCaseInstanceOperation(CommandContext commandContext, CaseIn
4040

4141
@Override
4242
public void internalExecute() {
43+
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
44+
if (cmmnEngineConfiguration.getEndCaseInstanceInterceptor() != null) {
45+
cmmnEngineConfiguration.getEndCaseInstanceInterceptor().beforeEndCaseInstance(caseInstanceEntity, getNewState());
46+
}
4347
deleteCaseInstance();
48+
if (cmmnEngineConfiguration.getEndCaseInstanceInterceptor() != null) {
49+
cmmnEngineConfiguration.getEndCaseInstanceInterceptor().afterEndCaseInstance(caseInstanceEntity.getId(), getNewState());
50+
}
4451
}
4552

4653
protected void deleteCaseInstance() {

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/CompleteCaseInstanceOperation.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package org.flowable.cmmn.engine.impl.agenda.operation;
1414

1515
import org.flowable.cmmn.api.runtime.CaseInstanceState;
16+
import org.flowable.cmmn.engine.CmmnEngineConfiguration;
1617
import org.flowable.cmmn.engine.impl.behavior.OnParentEndDependantActivityBehavior;
1718
import org.flowable.cmmn.engine.impl.event.FlowableCmmnEventBuilder;
1819
import org.flowable.cmmn.engine.impl.persistence.entity.CaseInstanceEntity;

modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/TerminateCaseInstanceOperation.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.HashMap;
2121

2222
import org.flowable.cmmn.api.runtime.CaseInstanceState;
23+
import org.flowable.cmmn.engine.CmmnEngineConfiguration;
2324
import org.flowable.cmmn.engine.impl.behavior.OnParentEndDependantActivityBehavior;
2425
import org.flowable.cmmn.engine.impl.callback.CallbackConstants;
2526
import org.flowable.cmmn.engine.impl.event.FlowableCmmnEventBuilder;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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.cmmn.engine.interceptor;
14+
15+
import org.flowable.cmmn.engine.impl.persistence.entity.CaseInstanceEntity;
16+
17+
public interface EndCaseInstanceInterceptor {
18+
19+
void beforeEndCaseInstance(CaseInstanceEntity caseInstance, String state);
20+
21+
void afterEndCaseInstance(String caseInstanceId, String state);
22+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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+
14+
package org.flowable.cmmn.test.runtime;
15+
16+
import static org.assertj.core.api.Assertions.assertThat;
17+
18+
import org.flowable.cmmn.api.runtime.CaseInstance;
19+
import org.flowable.cmmn.api.runtime.CaseInstanceState;
20+
import org.flowable.cmmn.engine.impl.persistence.entity.CaseInstanceEntity;
21+
import org.flowable.cmmn.engine.interceptor.EndCaseInstanceInterceptor;
22+
import org.flowable.cmmn.engine.test.CmmnDeployment;
23+
import org.flowable.cmmn.test.FlowableCmmnTestCase;
24+
import org.junit.jupiter.api.Test;
25+
26+
/**
27+
* @author Christopher Welsch
28+
*/
29+
public class CaseInstanceEndInterceptorTest extends FlowableCmmnTestCase {
30+
31+
@Test
32+
@CmmnDeployment(resources = "org/flowable/cmmn/test/runtime/oneHumanTaskCase.cmmn")
33+
public void testEndProcessInterceptorIsCalled() {
34+
try {
35+
TestEndCaseInstanceInterceptor testEndCaseInstanceInterceptor = new TestEndCaseInstanceInterceptor();
36+
cmmnEngineConfiguration.setEndCaseInstanceInterceptor(testEndCaseInstanceInterceptor);
37+
38+
cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("oneHumanTaskCase").start();
39+
cmmnTaskService.complete(cmmnTaskService.createTaskQuery().singleResult().getId());
40+
assertThat(testEndCaseInstanceInterceptor.beforeIsCalled).isTrue();
41+
assertThat(testEndCaseInstanceInterceptor.beforeState).isEqualTo(CaseInstanceState.COMPLETED);
42+
43+
assertThat(testEndCaseInstanceInterceptor.afterIsCalled).isTrue();
44+
assertThat(testEndCaseInstanceInterceptor.afterState).isEqualTo(CaseInstanceState.COMPLETED);
45+
} finally {
46+
cmmnEngineConfiguration.setEndCaseInstanceInterceptor(null);
47+
}
48+
}
49+
50+
@Test
51+
@CmmnDeployment(resources = "org/flowable/cmmn/test/runtime/oneHumanTaskCase.cmmn")
52+
public void testEndProcessInterceptorIsNotCalledForTermination() {
53+
try {
54+
TestEndCaseInstanceInterceptor testEndCaseInstanceInterceptor = new TestEndCaseInstanceInterceptor();
55+
cmmnEngineConfiguration.setEndCaseInstanceInterceptor(testEndCaseInstanceInterceptor);
56+
CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("oneHumanTaskCase").start();
57+
cmmnRuntimeService.terminateCaseInstance(caseInstance.getId());
58+
assertThat(testEndCaseInstanceInterceptor.beforeIsCalled).isTrue();
59+
assertThat(testEndCaseInstanceInterceptor.beforeState).isEqualTo(CaseInstanceState.TERMINATED);
60+
61+
assertThat(testEndCaseInstanceInterceptor.afterIsCalled).isTrue();
62+
assertThat(testEndCaseInstanceInterceptor.afterState).isEqualTo(CaseInstanceState.TERMINATED);
63+
} finally {
64+
cmmnEngineConfiguration.setEndCaseInstanceInterceptor(null);
65+
}
66+
}
67+
68+
public static class TestEndCaseInstanceInterceptor implements EndCaseInstanceInterceptor {
69+
70+
protected boolean beforeIsCalled = false;
71+
protected String beforeState = null;
72+
73+
protected boolean afterIsCalled = false;
74+
protected String afterState = null;
75+
76+
@Override
77+
public void beforeEndCaseInstance(CaseInstanceEntity caseInstance, String endingState) {
78+
beforeIsCalled = true;
79+
beforeState = endingState;
80+
}
81+
82+
@Override
83+
public void afterEndCaseInstance(String caseInstanceId, String endingState) {
84+
afterIsCalled = true;
85+
afterState = endingState;
86+
}
87+
}
88+
}

modules/flowable-engine/src/main/java/org/flowable/engine/impl/agenda/EndExecutionOperation.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.flowable.engine.impl.jobexecutor.AsyncCompleteCallActivityJobHandler;
4444
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
4545
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
46+
import org.flowable.engine.impl.runtime.callback.ProcessInstanceState;
4647
import org.flowable.engine.impl.util.CommandContextUtil;
4748
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
4849
import org.flowable.job.service.JobService;
@@ -183,6 +184,10 @@ protected void handleRegularExecution() {
183184
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
184185
ExecutionEntityManager executionEntityManager = processEngineConfiguration.getExecutionEntityManager();
185186

187+
if (processEngineConfiguration.getEndProcessInstanceInterceptor() != null) {
188+
processEngineConfiguration.getEndProcessInstanceInterceptor().beforeEndProcessInstance(execution, ProcessInstanceState.COMPLETED);
189+
}
190+
186191
// There will be a parent execution (or else we would be in the process instance handling method)
187192
ExecutionEntity parentExecution = executionEntityManager.findById(execution.getParentId());
188193

@@ -242,7 +247,6 @@ protected void handleRegularExecution() {
242247

243248
agenda.planEndExecutionOperation(subProcessParentExecution);
244249
}
245-
246250
return;
247251
}
248252
}
@@ -305,6 +309,10 @@ protected void handleRegularExecution() {
305309
}
306310

307311
}
312+
313+
if (processEngineConfiguration.getEndProcessInstanceInterceptor() != null) {
314+
processEngineConfiguration.getEndProcessInstanceInterceptor().afterEndProcessInstance(execution.getId(), ProcessInstanceState.COMPLETED);
315+
}
308316
}
309317

310318
protected ExecutionEntity handleSubProcessEnd(ExecutionEntityManager executionEntityManager, ExecutionEntity parentExecution, SubProcess subProcess) {

modules/flowable-engine/src/main/java/org/flowable/engine/impl/cfg/ProcessEngineConfigurationImpl.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@
348348
import org.flowable.engine.impl.variable.ParallelMultiInstanceLoopVariableType;
349349
import org.flowable.engine.interceptor.CreateExternalWorkerJobInterceptor;
350350
import org.flowable.engine.interceptor.CreateUserTaskInterceptor;
351+
import org.flowable.engine.interceptor.EndProcessInstanceInterceptor;
351352
import org.flowable.engine.interceptor.ExecutionQueryInterceptor;
352353
import org.flowable.engine.interceptor.HistoricProcessInstanceQueryInterceptor;
353354
import org.flowable.engine.interceptor.IdentityLinkInterceptor;
@@ -753,6 +754,8 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig
753754
protected BusinessCalendarManager businessCalendarManager;
754755

755756
protected StartProcessInstanceInterceptor startProcessInstanceInterceptor;
757+
protected EndProcessInstanceInterceptor endProcessInstanceInterceptor;
758+
756759
protected CreateUserTaskInterceptor createUserTaskInterceptor;
757760
protected UserTaskStateInterceptor userTaskStateInterceptor;
758761
protected CreateExternalWorkerJobInterceptor createExternalWorkerJobInterceptor;
@@ -3353,6 +3356,15 @@ public ProcessEngineConfigurationImpl setStartProcessInstanceInterceptor(StartPr
33533356
this.startProcessInstanceInterceptor = startProcessInstanceInterceptor;
33543357
return this;
33553358
}
3359+
3360+
public EndProcessInstanceInterceptor getEndProcessInstanceInterceptor() {
3361+
return endProcessInstanceInterceptor;
3362+
}
3363+
3364+
public ProcessEngineConfigurationImpl setEndProcessInstanceInterceptor(EndProcessInstanceInterceptor endProcessInstanceInterceptor) {
3365+
this.endProcessInstanceInterceptor = endProcessInstanceInterceptor;
3366+
return this;
3367+
}
33563368

33573369
public CreateUserTaskInterceptor getCreateUserTaskInterceptor() {
33583370
return createUserTaskInterceptor;

modules/flowable-engine/src/main/java/org/flowable/engine/impl/persistence/entity/ExecutionEntityManagerImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,10 @@ public void deleteProcessInstance(String processInstanceId, String deleteReason,
448448
public void deleteProcessInstance(String processInstanceId, String deleteReason, boolean cascade, boolean directDeleteInDatabase) {
449449
ExecutionEntity processInstanceExecution = findById(processInstanceId);
450450

451+
if (engineConfiguration.getEndProcessInstanceInterceptor() != null) {
452+
engineConfiguration.getEndProcessInstanceInterceptor().beforeEndProcessInstance(processInstanceExecution, ProcessInstanceState.CANCELLED);
453+
}
454+
451455
if (processInstanceExecution == null) {
452456
throw new FlowableObjectNotFoundException("No process instance found for id '" + processInstanceId + "'", ProcessInstance.class);
453457
}
@@ -473,6 +477,10 @@ public void deleteProcessInstance(String processInstanceId, String deleteReason,
473477
}
474478
}
475479
}
480+
481+
if (engineConfiguration.getEndProcessInstanceInterceptor() != null) {
482+
engineConfiguration.getEndProcessInstanceInterceptor().afterEndProcessInstance(processInstanceId, ProcessInstanceState.CANCELLED);
483+
}
476484
}
477485

478486
protected void deleteProcessInstanceCascade(ExecutionEntity execution, String state, String deleteReason, boolean deleteHistory, boolean directDeleteInDatabase) {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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.interceptor;
14+
15+
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
16+
17+
public interface EndProcessInstanceInterceptor {
18+
19+
void beforeEndProcessInstance(ExecutionEntity processInstance, String state);
20+
21+
void afterEndProcessInstance(String processInstanceId, String state);
22+
}

0 commit comments

Comments
 (0)