Skip to content
Merged
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 @@ -53,7 +53,7 @@ public static void bulkDeleteHistoricCaseInstances(Collection<String> caseInstan
}

HistoricVariableInstanceEntityManager historicVariableInstanceEntityManager = cmmnEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableInstanceEntityManager();
historicVariableInstanceEntityManager.bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeType(caseInstanceIds, ScopeTypes.CMMN);
historicVariableInstanceEntityManager.bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(caseInstanceIds, cmmnEngineConfiguration.getDependentScopeTypes());

TaskHelper.bulkDeleteHistoricTaskInstancesByCaseInstanceIds(caseInstanceIds, cmmnEngineConfiguration);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public void recordHistoricCaseInstanceDeleted(String caseInstanceId, String tena

HistoricVariableInstanceEntityManager historicVariableInstanceEntityManager = cmmnEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableInstanceEntityManager();
List<HistoricVariableInstanceEntity> historicVariableInstanceEntities = historicVariableInstanceEntityManager
.findHistoricalVariableInstancesByScopeIdAndScopeType(caseInstanceId, ScopeTypes.CMMN);
.findHistoricalVariableInstancesByScopeIdAndScopeTypes(caseInstanceId, cmmnEngineConfiguration.getDependentScopeTypes());
for (HistoricVariableInstanceEntity historicVariableInstanceEntity : historicVariableInstanceEntities) {
historicVariableInstanceEntityManager.delete(historicVariableInstanceEntity);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.flowable.cmmn.api.runtime.CaseInstance;
Expand All @@ -32,11 +34,16 @@
import org.flowable.common.engine.impl.persistence.entity.ByteArrayEntity;
import org.flowable.identitylink.api.IdentityLinkType;
import org.flowable.task.api.Task;
import org.flowable.variable.service.HistoricVariableService;
import org.flowable.variable.service.VariableServiceConfiguration;
import org.flowable.variable.service.impl.persistence.entity.HistoricVariableInstanceEntity;
import org.flowable.variable.service.impl.types.SerializableType;
import org.junit.jupiter.api.Test;

public class BulkCaseInstanceDeleteTest extends FlowableCmmnTestCase {

protected static final String TEST_DEPENDENT_SCOPE_TYPE = "testDependentScope";

@Test
@CmmnDeployment(resources = "org/flowable/cmmn/test/one-human-task-model.cmmn")
public void oneTaskTestWithVariables() {
Expand Down Expand Up @@ -417,6 +424,88 @@ public void deleteHistoricCaseInstanceRemovesReferenceScopeOrphans() {
}
}

@Test
@CmmnDeployment(resources = "org/flowable/cmmn/test/one-human-task-model.cmmn")
public void deleteHistoricCaseInstanceRemovesDependentScopeVariables() {
cmmnEngineConfiguration.addDependentScopeType(TEST_DEPENDENT_SCOPE_TYPE);
try {
CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("oneTaskCase").start();
HistoricVariableInstanceEntity dependentVariable = createDependentScopeHistoricVariable(caseInstance.getId());
String byteArrayId = dependentVariable.getByteArrayRef().getId();
assertThat(byteArrayId).isNotNull();

Task task = cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).singleResult();
cmmnTaskService.complete(task.getId());
waitForAsyncHistoryExecutorToProcessAllJobs();

cmmnHistoryService.deleteHistoricCaseInstance(caseInstance.getId());

assertThat(findHistoricVariableInstanceById(dependentVariable.getId())).isNull();
assertThat(findByteArrayById(byteArrayId)).isNull();
} finally {
cmmnEngineConfiguration.getDependentScopeTypes().remove(TEST_DEPENDENT_SCOPE_TYPE);
}
}

@Test
@CmmnDeployment(resources = "org/flowable/cmmn/test/one-human-task-model.cmmn")
public void bulkDeleteHistoricCaseInstancesRemovesDependentScopeVariables() {
cmmnEngineConfiguration.addDependentScopeType(TEST_DEPENDENT_SCOPE_TYPE);
try {
CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder().caseDefinitionKey("oneTaskCase").start();
HistoricVariableInstanceEntity dependentVariable = createDependentScopeHistoricVariable(caseInstance.getId());
String byteArrayId = dependentVariable.getByteArrayRef().getId();
assertThat(byteArrayId).isNotNull();

Task task = cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).singleResult();
cmmnTaskService.complete(task.getId());
waitForAsyncHistoryExecutorToProcessAllJobs();

cmmnHistoryService.bulkDeleteHistoricCaseInstances(Collections.singletonList(caseInstance.getId()));

assertThat(findHistoricVariableInstanceById(dependentVariable.getId())).isNull();
assertThat(findByteArrayById(byteArrayId)).isNull();
} finally {
cmmnEngineConfiguration.getDependentScopeTypes().remove(TEST_DEPENDENT_SCOPE_TYPE);
}
}

/**
* Mimics a consumer that records history for its own dependent scope type: the row is linked to the case instance
* through the scope id, but carries a scope type the regular variable APIs never see.
*/
protected HistoricVariableInstanceEntity createDependentScopeHistoricVariable(String caseInstanceId) {
String planItemInstanceId = cmmnRuntimeService.createPlanItemInstanceQuery().caseInstanceId(caseInstanceId)
.planItemInstanceState(PlanItemInstanceState.ACTIVE).singleResult().getId();
return cmmnEngineConfiguration.getCommandExecutor().execute(commandContext -> {
VariableServiceConfiguration variableServiceConfiguration = cmmnEngineConfiguration.getVariableServiceConfiguration();
HistoricVariableService historicVariableService = variableServiceConfiguration.getHistoricVariableService();

HistoricVariableInstanceEntity historicVariable = historicVariableService.createHistoricVariableInstance();
historicVariable.setName("dependentScopeVariable");
historicVariable.setScopeId(caseInstanceId);
historicVariable.setSubScopeId(planItemInstanceId);
historicVariable.setScopeType(TEST_DEPENDENT_SCOPE_TYPE);
historicVariable.setVariableType(variableServiceConfiguration.getVariableTypes().getVariableType(SerializableType.TYPE_NAME));
historicVariable.setCreateTime(new Date());
historicVariable.setLastUpdatedTime(historicVariable.getCreateTime());
historicVariable.setBytes("dependent scope value".getBytes(StandardCharsets.UTF_8));

historicVariableService.insertHistoricVariableInstance(historicVariable);
return historicVariable;
});
}

protected HistoricVariableInstanceEntity findHistoricVariableInstanceById(String id) {
return cmmnEngineConfiguration.getCommandExecutor().execute(commandContext -> cmmnEngineConfiguration
.getVariableServiceConfiguration().getHistoricVariableService().getHistoricVariableInstance(id));
}

protected ByteArrayEntity findByteArrayById(String id) {
return cmmnEngineConfiguration.getCommandExecutor().execute(commandContext -> CommandContextUtil
.getCmmnEngineConfiguration(commandContext).getByteArrayEntityManager().findById(id));
}

protected void validateEmptyHistoricDataForCaseInstance(String caseInstanceId) {
assertThat(cmmnHistoryService.createHistoricVariableInstanceQuery().caseInstanceId(caseInstanceId).list()).hasSize(0);
assertThat(cmmnHistoryService.getHistoricIdentityLinksForCaseInstance(caseInstanceId)).hasSize(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.flowable.task.service.impl.HistoricTaskInstanceQueryImpl;
import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.variable.service.HistoricVariableService;
import org.flowable.variable.service.impl.persistence.entity.VariableInstanceEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -136,8 +137,12 @@ public void recordProcessInstanceDeleted(String processInstanceId, String proces
getHistoricDetailEntityManager().deleteHistoricDetailsByProcessInstanceId(processInstanceId);

if (getHistoryConfigurationSettings().isHistoryEnabledForVariables(processDefinitionId)) {
processEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService()
.deleteHistoricVariableInstancesByProcessInstanceId(processInstanceId);
HistoricVariableService historicVariableService = processEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService();
historicVariableService.deleteHistoricVariableInstancesByProcessInstanceId(processInstanceId);

// Variables stored under a dependent scope type have no process instance id, they are linked to the process instance through the scope id
historicVariableService.deleteHistoricVariableInstancesByScopeIdAndScopeTypes(processInstanceId,
processEngineConfiguration.getDependentScopeTypes());
}
getHistoricActivityInstanceEntityManager().deleteHistoricActivityInstancesByProcessInstanceId(processInstanceId);
TaskHelper.deleteHistoricTaskInstancesByProcessInstanceId(processInstanceId);
Expand Down Expand Up @@ -178,7 +183,12 @@ public void recordDeleteHistoricProcessInstancesByProcessDefinitionId(String pro
public void recordBulkDeleteProcessInstances(Collection<String> processInstanceIds) {
if (isHistoryEnabled() && processInstanceIds != null && !processInstanceIds.isEmpty()) {
getHistoricDetailEntityManager().bulkDeleteHistoricDetailsByProcessInstanceIds(processInstanceIds);
processEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService().bulkDeleteHistoricVariableInstancesByProcessInstanceIds(processInstanceIds);
HistoricVariableService historicVariableService = processEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableService();
historicVariableService.bulkDeleteHistoricVariableInstancesByProcessInstanceIds(processInstanceIds);

// Variables stored under a dependent scope type have no process instance id, they are linked to the process instance through the scope id
historicVariableService.bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(processInstanceIds,
processEngineConfiguration.getDependentScopeTypes());
getHistoricActivityInstanceEntityManager().bulkDeleteHistoricActivityInstancesByProcessInstanceIds(processInstanceIds);
TaskHelper.bulkDeleteHistoricTaskInstancesForProcessInstanceIds(processInstanceIds);
processEngineConfiguration.getIdentityLinkServiceConfiguration().getHistoricIdentityLinkService().bulkDeleteHistoricIdentityLinksForProcessInstanceIds(processInstanceIds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.flowable.common.engine.api.FlowableObjectNotFoundException;
Expand All @@ -34,11 +36,16 @@
import org.flowable.entitylink.api.EntityLinkType;
import org.flowable.entitylink.api.history.HistoricEntityLink;
import org.flowable.task.api.Task;
import org.flowable.variable.service.HistoricVariableService;
import org.flowable.variable.service.VariableServiceConfiguration;
import org.flowable.variable.service.impl.persistence.entity.HistoricVariableInstanceEntity;
import org.flowable.variable.service.impl.types.SerializableType;
import org.junit.jupiter.api.Test;

public class BulkDeleteHistoricProcessInstanceTest extends PluggableFlowableTestCase {

protected static final String TEST_DEPENDENT_SCOPE_TYPE = "testDependentScope";

@Test
@Deployment(resources = { "org/flowable/engine/test/bpmn/oneTask.bpmn20.xml" })
public void oneTaskTestWithVariables() {
Expand Down Expand Up @@ -554,6 +561,87 @@ public void bulkDeleteHistoricProcessInstancesRemovesReferenceScopeOrphans() {
}
}

@Test
@Deployment(resources = { "org/flowable/engine/test/bpmn/oneTask.bpmn20.xml" })
public void deleteHistoricProcessInstanceRemovesDependentScopeVariables() {
processEngineConfiguration.addDependentScopeType(TEST_DEPENDENT_SCOPE_TYPE);
try {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("startToEnd");
HistoricVariableInstanceEntity dependentVariable = createDependentScopeHistoricVariable(processInstance.getId());
String byteArrayId = dependentVariable.getByteArrayRef().getId();
assertThat(byteArrayId).isNotNull();

Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
taskService.complete(task.getId());
waitForHistoryJobExecutorToProcessAllJobs(10000, 400);

historyService.deleteHistoricProcessInstance(processInstance.getId());

assertThat(findHistoricVariableInstanceById(dependentVariable.getId())).isNull();
assertThat(findByteArrayById(byteArrayId)).isNull();
} finally {
processEngineConfiguration.getDependentScopeTypes().remove(TEST_DEPENDENT_SCOPE_TYPE);
}
}

@Test
@Deployment(resources = { "org/flowable/engine/test/bpmn/oneTask.bpmn20.xml" })
public void bulkDeleteHistoricProcessInstancesRemovesDependentScopeVariables() {
processEngineConfiguration.addDependentScopeType(TEST_DEPENDENT_SCOPE_TYPE);
try {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("startToEnd");
HistoricVariableInstanceEntity dependentVariable = createDependentScopeHistoricVariable(processInstance.getId());
String byteArrayId = dependentVariable.getByteArrayRef().getId();
assertThat(byteArrayId).isNotNull();

Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
taskService.complete(task.getId());
waitForHistoryJobExecutorToProcessAllJobs(10000, 400);

historyService.bulkDeleteHistoricProcessInstances(Collections.singletonList(processInstance.getId()));

assertThat(findHistoricVariableInstanceById(dependentVariable.getId())).isNull();
assertThat(findByteArrayById(byteArrayId)).isNull();
} finally {
processEngineConfiguration.getDependentScopeTypes().remove(TEST_DEPENDENT_SCOPE_TYPE);
}
}

/**
* Mimics a consumer that records history for its own dependent scope type: the row has no process instance id,
* only the process instance id as scope id and an execution id as sub scope id.
*/
protected HistoricVariableInstanceEntity createDependentScopeHistoricVariable(String processInstanceId) {
String executionId = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).onlyChildExecutions().singleResult().getId();
return managementService.executeCommand(commandContext -> {
VariableServiceConfiguration variableServiceConfiguration = processEngineConfiguration.getVariableServiceConfiguration();
HistoricVariableService historicVariableService = variableServiceConfiguration.getHistoricVariableService();

HistoricVariableInstanceEntity historicVariable = historicVariableService.createHistoricVariableInstance();
historicVariable.setName("dependentScopeVariable");
historicVariable.setScopeId(processInstanceId);
historicVariable.setSubScopeId(executionId);
historicVariable.setScopeType(TEST_DEPENDENT_SCOPE_TYPE);
historicVariable.setVariableType(variableServiceConfiguration.getVariableTypes().getVariableType(SerializableType.TYPE_NAME));
historicVariable.setCreateTime(new Date());
historicVariable.setLastUpdatedTime(historicVariable.getCreateTime());
historicVariable.setBytes("dependent scope value".getBytes(StandardCharsets.UTF_8));

historicVariableService.insertHistoricVariableInstance(historicVariable);
return historicVariable;
});
}

protected HistoricVariableInstanceEntity findHistoricVariableInstanceById(String id) {
return managementService.executeCommand(commandContext -> processEngineConfiguration.getVariableServiceConfiguration()
.getHistoricVariableService().getHistoricVariableInstance(id));
}

protected ByteArrayEntity findByteArrayById(String id) {
return managementService.executeCommand(
commandContext -> CommandContextUtil.getByteArrayEntityManager(commandContext).findById(id));
}

protected void validateEmptyHistoricDataForProcessInstance(String processInstanceId) {
assertThat(historyService.createHistoricDetailQuery().processInstanceId(processInstanceId).list()).hasSize(0);
assertThat(historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list()).hasSize(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,14 @@ public interface HistoricVariableService {
void deleteHistoricVariableInstancesByProcessInstanceId(String processInstanceId);

void deleteHistoricVariableInstancesByTaskId(String taskId);

void deleteHistoricVariableInstancesByScopeIdAndScopeTypes(String scopeId, Collection<String> scopeTypes);

void bulkDeleteHistoricVariableInstancesByProcessInstanceIds(Collection<String> processInstanceIds);

void bulkDeleteHistoricVariableInstancesByTaskIds(Collection<String> taskIds);

void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(Collection<String> scopeIds, Collection<String> scopeTypes);

void deleteHistoricVariableInstancesForNonExistingProcessInstances();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ public void deleteHistoricVariableInstancesByTaskId(String taskId) {
getHistoricVariableInstanceEntityManager().deleteHistoricVariableInstancesByTaskId(taskId);
}

@Override
public void deleteHistoricVariableInstancesByScopeIdAndScopeTypes(String scopeId, Collection<String> scopeTypes) {
getHistoricVariableInstanceEntityManager().deleteHistoricVariableInstancesByScopeIdAndScopeTypes(scopeId, scopeTypes);
}

@Override
public void bulkDeleteHistoricVariableInstancesByProcessInstanceIds(Collection<String> processInstanceIds) {
getHistoricVariableInstanceEntityManager().bulkDeleteHistoricVariableInstancesByProcessInstanceIds(processInstanceIds);
Expand All @@ -118,6 +123,11 @@ public void bulkDeleteHistoricVariableInstancesByTaskIds(Collection<String> task
getHistoricVariableInstanceEntityManager().bulkDeleteHistoricVariableInstancesByTaskIds(taskIds);
}

@Override
public void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(Collection<String> scopeIds, Collection<String> scopeTypes) {
getHistoricVariableInstanceEntityManager().bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(scopeIds, scopeTypes);
}

@Override
public void deleteHistoricVariableInstancesForNonExistingProcessInstances() {
getHistoricVariableInstanceEntityManager().deleteHistoricVariableInstancesForNonExistingProcessInstances();
Expand Down
Loading