diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/CmmnHistoryHelper.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/CmmnHistoryHelper.java index a89a240ea20..bece911daa4 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/CmmnHistoryHelper.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/CmmnHistoryHelper.java @@ -53,7 +53,7 @@ public static void bulkDeleteHistoricCaseInstances(Collection caseInstan } HistoricVariableInstanceEntityManager historicVariableInstanceEntityManager = cmmnEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableInstanceEntityManager(); - historicVariableInstanceEntityManager.bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeType(caseInstanceIds, ScopeTypes.CMMN); + historicVariableInstanceEntityManager.bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(caseInstanceIds, cmmnEngineConfiguration.getDependentScopeTypes()); TaskHelper.bulkDeleteHistoricTaskInstancesByCaseInstanceIds(caseInstanceIds, cmmnEngineConfiguration); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/DefaultCmmnHistoryManager.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/DefaultCmmnHistoryManager.java index 39694e6de48..17c24193bdf 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/DefaultCmmnHistoryManager.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/history/DefaultCmmnHistoryManager.java @@ -218,7 +218,7 @@ public void recordHistoricCaseInstanceDeleted(String caseInstanceId, String tena HistoricVariableInstanceEntityManager historicVariableInstanceEntityManager = cmmnEngineConfiguration.getVariableServiceConfiguration().getHistoricVariableInstanceEntityManager(); List historicVariableInstanceEntities = historicVariableInstanceEntityManager - .findHistoricalVariableInstancesByScopeIdAndScopeType(caseInstanceId, ScopeTypes.CMMN); + .findHistoricalVariableInstancesByScopeIdAndScopeTypes(caseInstanceId, cmmnEngineConfiguration.getDependentScopeTypes()); for (HistoricVariableInstanceEntity historicVariableInstanceEntity : historicVariableInstanceEntities) { historicVariableInstanceEntityManager.delete(historicVariableInstanceEntity); } diff --git a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/history/BulkCaseInstanceDeleteTest.java b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/history/BulkCaseInstanceDeleteTest.java index 0913788042d..4e9d205cb67 100644 --- a/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/history/BulkCaseInstanceDeleteTest.java +++ b/modules/flowable-cmmn-engine/src/test/java/org/flowable/cmmn/test/history/BulkCaseInstanceDeleteTest.java @@ -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; @@ -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() { @@ -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); diff --git a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/history/DefaultHistoryManager.java b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/history/DefaultHistoryManager.java index eb37b1e2fea..e3690725e18 100644 --- a/modules/flowable-engine/src/main/java/org/flowable/engine/impl/history/DefaultHistoryManager.java +++ b/modules/flowable-engine/src/main/java/org/flowable/engine/impl/history/DefaultHistoryManager.java @@ -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; @@ -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); @@ -178,7 +183,12 @@ public void recordDeleteHistoricProcessInstancesByProcessDefinitionId(String pro public void recordBulkDeleteProcessInstances(Collection 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); diff --git a/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/BulkDeleteHistoricProcessInstanceTest.java b/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/BulkDeleteHistoricProcessInstanceTest.java index 5dd76ec9785..24faae3ca0f 100644 --- a/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/BulkDeleteHistoricProcessInstanceTest.java +++ b/modules/flowable-engine/src/test/java/org/flowable/engine/test/history/BulkDeleteHistoricProcessInstanceTest.java @@ -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; @@ -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() { @@ -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); diff --git a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/HistoricVariableService.java b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/HistoricVariableService.java index e11a521ec1d..94c36add02b 100644 --- a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/HistoricVariableService.java +++ b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/HistoricVariableService.java @@ -48,10 +48,14 @@ public interface HistoricVariableService { void deleteHistoricVariableInstancesByProcessInstanceId(String processInstanceId); void deleteHistoricVariableInstancesByTaskId(String taskId); + + void deleteHistoricVariableInstancesByScopeIdAndScopeTypes(String scopeId, Collection scopeTypes); void bulkDeleteHistoricVariableInstancesByProcessInstanceIds(Collection processInstanceIds); void bulkDeleteHistoricVariableInstancesByTaskIds(Collection taskIds); + + void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(Collection scopeIds, Collection scopeTypes); void deleteHistoricVariableInstancesForNonExistingProcessInstances(); diff --git a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/HistoricVariableServiceImpl.java b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/HistoricVariableServiceImpl.java index a523fdb3fad..1db47962440 100644 --- a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/HistoricVariableServiceImpl.java +++ b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/HistoricVariableServiceImpl.java @@ -108,6 +108,11 @@ public void deleteHistoricVariableInstancesByTaskId(String taskId) { getHistoricVariableInstanceEntityManager().deleteHistoricVariableInstancesByTaskId(taskId); } + @Override + public void deleteHistoricVariableInstancesByScopeIdAndScopeTypes(String scopeId, Collection scopeTypes) { + getHistoricVariableInstanceEntityManager().deleteHistoricVariableInstancesByScopeIdAndScopeTypes(scopeId, scopeTypes); + } + @Override public void bulkDeleteHistoricVariableInstancesByProcessInstanceIds(Collection processInstanceIds) { getHistoricVariableInstanceEntityManager().bulkDeleteHistoricVariableInstancesByProcessInstanceIds(processInstanceIds); @@ -118,6 +123,11 @@ public void bulkDeleteHistoricVariableInstancesByTaskIds(Collection task getHistoricVariableInstanceEntityManager().bulkDeleteHistoricVariableInstancesByTaskIds(taskIds); } + @Override + public void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(Collection scopeIds, Collection scopeTypes) { + getHistoricVariableInstanceEntityManager().bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(scopeIds, scopeTypes); + } + @Override public void deleteHistoricVariableInstancesForNonExistingProcessInstances() { getHistoricVariableInstanceEntityManager().deleteHistoricVariableInstancesForNonExistingProcessInstances(); diff --git a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/HistoricVariableInstanceEntityManager.java b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/HistoricVariableInstanceEntityManager.java index 6b1f23886f6..0e8a51a64f5 100644 --- a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/HistoricVariableInstanceEntityManager.java +++ b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/HistoricVariableInstanceEntityManager.java @@ -48,6 +48,8 @@ public interface HistoricVariableInstanceEntityManager extends EntityManager findHistoricalVariableInstancesByScopeIdAndScopeType(String scopeId, String scopeType, Collection variableNames); + List findHistoricalVariableInstancesByScopeIdAndScopeTypes(String scopeId, Collection scopeTypes); + List findHistoricalVariableInstancesBySubScopeIdAndScopeType(String subScopeId, String scopeType); long findHistoricVariableInstanceCountByQueryCriteria(HistoricVariableInstanceQueryImpl historicProcessVariableQuery); @@ -59,6 +61,8 @@ public interface HistoricVariableInstanceEntityManager extends EntityManager scopeTypes); void bulkDeleteHistoricVariableInstancesByProcessInstanceIds(Collection processInstanceIds); @@ -66,6 +70,8 @@ public interface HistoricVariableInstanceEntityManager extends EntityManager scopeIds, String scopeType); + void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(Collection scopeIds, Collection scopeTypes); + void deleteHistoricVariableInstancesForNonExistingProcessInstances(); void deleteHistoricVariableInstancesForNonExistingCaseInstances(); diff --git a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/HistoricVariableInstanceEntityManagerImpl.java b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/HistoricVariableInstanceEntityManagerImpl.java index 4e2db08613c..26685ed61bc 100644 --- a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/HistoricVariableInstanceEntityManagerImpl.java +++ b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/HistoricVariableInstanceEntityManagerImpl.java @@ -106,6 +106,14 @@ public void deleteHistoricVariableInstanceByProcessInstanceId(final String histo } } + @Override + public void deleteHistoricVariableInstancesByScopeIdAndScopeTypes(String scopeId, Collection scopeTypes) { + List historicVariables = dataManager.findHistoricalVariableInstancesByScopeIdAndScopeTypes(scopeId, scopeTypes); + for (HistoricVariableInstanceEntity historicVariable : historicVariables) { + delete(historicVariable); + } + } + @Override public long findHistoricVariableInstanceCountByQueryCriteria(HistoricVariableInstanceQueryImpl historicProcessVariableQuery) { return dataManager.findHistoricVariableInstanceCountByQueryCriteria(historicProcessVariableQuery); @@ -147,6 +155,11 @@ public List findHistoricalVariableInstancesBySco return dataManager.findHistoricalVariableInstancesByScopeIdAndScopeType(scopeId, scopeType, variableNames); } + @Override + public List findHistoricalVariableInstancesByScopeIdAndScopeTypes(String scopeId, Collection scopeTypes) { + return dataManager.findHistoricalVariableInstancesByScopeIdAndScopeTypes(scopeId, scopeTypes); + } + @Override public List findHistoricalVariableInstancesBySubScopeIdAndScopeType(String subScopeId, String scopeType) { return dataManager.findHistoricalVariableInstancesBySubScopeIdAndScopeType(subScopeId, scopeType); @@ -175,6 +188,11 @@ public void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeType(Collection dataManager.bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeType(scopeIds, scopeType); } + @Override + public void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(Collection scopeIds, Collection scopeTypes) { + dataManager.bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(scopeIds, scopeTypes); + } + @Override public void deleteHistoricVariableInstancesForNonExistingProcessInstances() { dataManager.deleteHistoricVariableInstancesForNonExistingProcessInstances(); diff --git a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/HistoricVariableInstanceDataManager.java b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/HistoricVariableInstanceDataManager.java index 76af032399f..f37b81a20e9 100644 --- a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/HistoricVariableInstanceDataManager.java +++ b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/HistoricVariableInstanceDataManager.java @@ -42,6 +42,8 @@ public interface HistoricVariableInstanceDataManager extends DataManager findHistoricalVariableInstancesByScopeIdAndScopeType(String scopeId, String scopeType, Collection variableNames); + List findHistoricalVariableInstancesByScopeIdAndScopeTypes(String scopeId, Collection scopeTypes); + List findHistoricalVariableInstancesBySubScopeIdAndScopeType(String subScopeId, String scopeType); List findHistoricVariableInstancesByNativeQuery(Map parameterMap); @@ -54,6 +56,8 @@ public interface HistoricVariableInstanceDataManager extends DataManager scopeIds, String scopeType); + void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(Collection scopeIds, Collection scopeTypes); + void deleteHistoricVariableInstancesForNonExistingProcessInstances(); void deleteHistoricVariableInstancesForNonExistingCaseInstances(); diff --git a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/impl/MybatisHistoricVariableInstanceDataManager.java b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/impl/MybatisHistoricVariableInstanceDataManager.java index 05bd1a71dc4..fa63340a57c 100644 --- a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/impl/MybatisHistoricVariableInstanceDataManager.java +++ b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/impl/MybatisHistoricVariableInstanceDataManager.java @@ -13,6 +13,7 @@ package org.flowable.variable.service.impl.persistence.entity.data.impl; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -28,6 +29,7 @@ import org.flowable.variable.service.impl.persistence.entity.data.HistoricVariableInstanceDataManager; import org.flowable.variable.service.impl.persistence.entity.data.impl.cachematcher.HistoricVariableInstanceByProcInstMatcher; import org.flowable.variable.service.impl.persistence.entity.data.impl.cachematcher.HistoricVariableInstanceByScopeIdAndScopeTypeMatcher; +import org.flowable.variable.service.impl.persistence.entity.data.impl.cachematcher.HistoricVariableInstanceByScopeIdAndScopeTypesMatcher; import org.flowable.variable.service.impl.persistence.entity.data.impl.cachematcher.HistoricVariableInstanceBySubScopeIdAndScopeTypeMatcher; import org.flowable.variable.service.impl.persistence.entity.data.impl.cachematcher.HistoricVariableInstanceByTaskIdMatcher; @@ -45,6 +47,9 @@ public class MybatisHistoricVariableInstanceDataManager extends AbstractDataMana protected CachedEntityMatcher historicVariableInstanceByScopeIdAndScopeTypeMatcher = new HistoricVariableInstanceByScopeIdAndScopeTypeMatcher(); + protected CachedEntityMatcher historicVariableInstanceByScopeIdAndScopeTypesMatcher + = new HistoricVariableInstanceByScopeIdAndScopeTypesMatcher(); + protected CachedEntityMatcher historicVariableInstanceBySubScopeIdAndScopeTypeMatcher = new HistoricVariableInstanceBySubScopeIdAndScopeTypeMatcher(); @@ -118,12 +123,24 @@ public List findHistoricalVariableInstancesBySco return getList("selectHistoricVariableInstanceByScopeIdAndScopeType", params, historicVariableInstanceByScopeIdAndScopeTypeMatcher, true); } + @Override + public List findHistoricalVariableInstancesByScopeIdAndScopeTypes(String scopeId, Collection scopeTypes) { + if (scopeTypes == null || scopeTypes.isEmpty()) { + return Collections.emptyList(); + } + + Map params = new HashMap<>(2); + params.put("scopeId", scopeId); + params.put("scopeTypes", scopeTypes); + return getList("selectHistoricVariableInstanceByScopeIdAndScopeTypes", params, historicVariableInstanceByScopeIdAndScopeTypesMatcher, true); + } + @Override public List findHistoricalVariableInstancesBySubScopeIdAndScopeType(String subScopeId, String scopeType) { Map params = new HashMap<>(2); params.put("subScopeId", subScopeId); params.put("scopeType", scopeType); - return getList("selectHistoricVariableInstanceByScopeIdAndScopeType", params, historicVariableInstanceByScopeIdAndScopeTypeMatcher, true); + return getList("selectHistoricVariableInstanceBySubScopeIdAndScopeType", params, historicVariableInstanceBySubScopeIdAndScopeTypeMatcher, true); } @Override @@ -162,6 +179,21 @@ public void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeType(Collection getDbSqlSession().delete("bulkDeleteHistoricVariableInstancesForScopeIdsAndScopeType", params, HistoricVariableInstanceEntity.class); } + @Override + public void bulkDeleteHistoricVariableInstancesByScopeIdsAndScopeTypes(Collection scopeIds, Collection scopeTypes) { + if (scopeTypes == null || scopeTypes.isEmpty()) { + return; + } + + Map params = new HashMap<>(2); + params.put("scopeIds", createSafeInValuesList(scopeIds)); + params.put("scopeTypes", scopeTypes); + + // Using HistoricVariableInstanceEntity as the entity, because the deletion order of the ByteArrayEntity is after the HistoricVariableInstanceEntity + getDbSqlSession().delete("bulkDeleteBytesForHistoricVariableInstancesForScopeIdsAndScopeTypes", params, HistoricVariableInstanceEntity.class); + getDbSqlSession().delete("bulkDeleteHistoricVariableInstancesForScopeIdsAndScopeTypes", params, HistoricVariableInstanceEntity.class); + } + @Override public void deleteHistoricVariableInstancesForNonExistingProcessInstances() { // Using HistoricVariableInstanceEntity as the entity, because the deletion order of the ByteArrayEntity is after the HistoricVariableInstanceEntity diff --git a/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/impl/cachematcher/HistoricVariableInstanceByScopeIdAndScopeTypesMatcher.java b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/impl/cachematcher/HistoricVariableInstanceByScopeIdAndScopeTypesMatcher.java new file mode 100644 index 00000000000..d9b97311fb1 --- /dev/null +++ b/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/persistence/entity/data/impl/cachematcher/HistoricVariableInstanceByScopeIdAndScopeTypesMatcher.java @@ -0,0 +1,35 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.variable.service.impl.persistence.entity.data.impl.cachematcher; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; + +import org.flowable.common.engine.impl.persistence.cache.CachedEntityMatcherAdapter; +import org.flowable.variable.service.impl.persistence.entity.HistoricVariableInstanceEntity; + +/** + * @author Filip Hrisafov + */ +public class HistoricVariableInstanceByScopeIdAndScopeTypesMatcher extends CachedEntityMatcherAdapter { + + @Override + @SuppressWarnings("unchecked") + public boolean isRetained(HistoricVariableInstanceEntity historicVariableInstanceEntity, Object parameter) { + Map map = (Map) parameter; + return Objects.equals(historicVariableInstanceEntity.getScopeId(), map.get("scopeId")) + && ((Collection) map.get("scopeTypes")).contains(historicVariableInstanceEntity.getScopeType()); + } + +} diff --git a/modules/flowable-variable-service/src/main/resources/org/flowable/variable/service/db/mapping/entity/HistoricVariableInstance.xml b/modules/flowable-variable-service/src/main/resources/org/flowable/variable/service/db/mapping/entity/HistoricVariableInstance.xml index b00805f9c42..6b80b43e7ad 100644 --- a/modules/flowable-variable-service/src/main/resources/org/flowable/variable/service/db/mapping/entity/HistoricVariableInstance.xml +++ b/modules/flowable-variable-service/src/main/resources/org/flowable/variable/service/db/mapping/entity/HistoricVariableInstance.xml @@ -247,6 +247,45 @@ ) and SCOPE_TYPE_ = #{scopeType, jdbcType=NVARCHAR} + + + delete BYTES_ from ${prefix}ACT_GE_BYTEARRAY BYTES_ + where BYTES_.ID_ in ( + select VARINST.BYTEARRAY_ID_ + from ${prefix}ACT_HI_VARINST VARINST + where + ( + + or + + VARINST.SCOPE_ID_ in + + #{scopeId, jdbcType=NVARCHAR} + + ) + and VARINST.SCOPE_TYPE_ in + + #{scopeType, jdbcType=NVARCHAR} + + ) + + + + delete from ${prefix}ACT_HI_VARINST where + ( + + or + + SCOPE_ID_ in + + #{scopeId, jdbcType=NVARCHAR} + + ) + and SCOPE_TYPE_ in + + #{scopeType, jdbcType=NVARCHAR} + + delete VARINST from ${prefix}ACT_HI_VARINST VARINST where VARINST.PROC_INST_ID_ is not null and VARINST.PROC_INST_ID_ != '' and @@ -550,6 +589,16 @@ + +