diff --git a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/runtime/PlanItemInstanceTransitionBuilder.java b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/runtime/PlanItemInstanceTransitionBuilder.java index 16b97554b7a..32a6dd57974 100644 --- a/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/runtime/PlanItemInstanceTransitionBuilder.java +++ b/modules/flowable-cmmn-api/src/main/java/org/flowable/cmmn/api/runtime/PlanItemInstanceTransitionBuilder.java @@ -113,6 +113,16 @@ public interface PlanItemInstanceTransitionBuilder { * Starts a plan item instance, this typically will executes it associated behavior. */ void start(); + + /** + * Suspend a plan item instance. + */ + void suspend(); + + /** + * Sets the plan item instance to available state. + */ + void resume(); /** * Manually terminates a plan item instance. diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/CmmnEngineAgenda.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/CmmnEngineAgenda.java index 5423f6eff63..0f9779b2f55 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/CmmnEngineAgenda.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/CmmnEngineAgenda.java @@ -74,11 +74,15 @@ public interface CmmnEngineAgenda extends Agenda { void planExitPlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity, String exitCriterionId, String exitType, String exitEventType); + void planSuspendPlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity); + void planTerminatePlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity, String exitType, String exitEventType); void planTriggerPlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity); void planChangePlanItemInstanceToAvailableOperation(PlanItemInstanceEntity planItemInstanceEntity); + + void planResumePlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity); void planCompleteCaseInstanceOperation(CaseInstanceEntity caseInstanceEntity); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/DefaultCmmnEngineAgenda.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/DefaultCmmnEngineAgenda.java index 80c18b700f0..3963d756677 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/DefaultCmmnEngineAgenda.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/DefaultCmmnEngineAgenda.java @@ -41,7 +41,9 @@ import org.flowable.cmmn.engine.impl.agenda.operation.ReactivateCaseInstanceOperation; import org.flowable.cmmn.engine.impl.agenda.operation.ReactivatePlanItemInstanceOperation; import org.flowable.cmmn.engine.impl.agenda.operation.ReactivatePlanModelInstanceOperation; +import org.flowable.cmmn.engine.impl.agenda.operation.ResumePlanItemInstanceOperation; import org.flowable.cmmn.engine.impl.agenda.operation.StartPlanItemInstanceOperation; +import org.flowable.cmmn.engine.impl.agenda.operation.SuspendPlanItemInstanceOperation; import org.flowable.cmmn.engine.impl.agenda.operation.TerminateCaseInstanceOperation; import org.flowable.cmmn.engine.impl.agenda.operation.TerminatePlanItemInstanceOperation; import org.flowable.cmmn.engine.impl.agenda.operation.TriggerPlanItemInstanceOperation; @@ -253,6 +255,11 @@ public void planOccurPlanItemInstanceOperation(PlanItemInstanceEntity planItemIn public void planExitPlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity, String exitCriterionId, String exitType, String exitEventType) { addOperation(new ExitPlanItemInstanceOperation(commandContext, planItemInstanceEntity, exitCriterionId, exitType, exitEventType)); } + + @Override + public void planSuspendPlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity) { + addOperation(new SuspendPlanItemInstanceOperation(commandContext, planItemInstanceEntity)); + } @Override public void planTerminatePlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity, String exitType, String exitEventType) { @@ -263,6 +270,11 @@ public void planTerminatePlanItemInstanceOperation(PlanItemInstanceEntity planIt public void planChangePlanItemInstanceToAvailableOperation(PlanItemInstanceEntity planItemInstanceEntity) { addOperation(new ChangePlanItemInstanceToAvailableOperation(commandContext, planItemInstanceEntity)); } + + @Override + public void planResumePlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity) { + addOperation(new ResumePlanItemInstanceOperation(commandContext, planItemInstanceEntity)); + } @Override public void planTriggerPlanItemInstanceOperation(PlanItemInstanceEntity planItemInstanceEntity) { diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/ResumePlanItemInstanceOperation.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/ResumePlanItemInstanceOperation.java new file mode 100644 index 00000000000..0745eeff2da --- /dev/null +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/ResumePlanItemInstanceOperation.java @@ -0,0 +1,82 @@ +/* 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.cmmn.engine.impl.agenda.operation; + +import java.util.List; + +import org.flowable.cmmn.api.runtime.PlanItemInstanceState; +import org.flowable.cmmn.engine.CmmnEngineConfiguration; +import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity; +import org.flowable.cmmn.engine.impl.util.CommandContextUtil; +import org.flowable.cmmn.model.PlanItemDefinition; +import org.flowable.cmmn.model.PlanItemTransition; +import org.flowable.cmmn.model.TimerEventListener; +import org.flowable.common.engine.api.FlowableIllegalStateException; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.job.service.impl.persistence.entity.SuspendedJobEntity; + +/** + * @author Tijs Rademakers + */ +public class ResumePlanItemInstanceOperation extends AbstractChangePlanItemInstanceStateOperation { + + public ResumePlanItemInstanceOperation(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) { + super(commandContext, planItemInstanceEntity); + } + + @Override + public String getLifeCycleTransition() { + return PlanItemTransition.SUSPEND; + } + + @Override + public String getNewState() { + return PlanItemInstanceState.AVAILABLE; + } + + @Override + protected void internalExecute() { + planItemInstanceEntity.setLastAvailableTime(getCurrentTime(commandContext)); + + PlanItemDefinition planItemDefinition = planItemInstanceEntity.getPlanItem().getPlanItemDefinition(); + if (planItemDefinition instanceof TimerEventListener) { + CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext); + List suspendedJobs = cmmnEngineConfiguration.getJobServiceConfiguration().getSuspendedJobEntityManager().findJobsBySubScopeId(planItemInstanceEntity.getId()); + if (suspendedJobs != null && !suspendedJobs.isEmpty()) { + cmmnEngineConfiguration.getJobServiceConfiguration().getJobService().activateSuspendedJob(suspendedJobs.get(0)); + } + } + + CommandContextUtil.getCmmnHistoryManager(commandContext).recordPlanItemInstanceAvailable(planItemInstanceEntity); + } + + @Override + public boolean isStateNotChanged(String oldState, String newState) { + if (oldState != null && !PlanItemInstanceState.SUSPENDED.equals(oldState)) { + throw new FlowableIllegalStateException("plan item instance can only be resumed if the state is suspended"); + } + + return oldState != null && oldState.equals(newState) && abortOperationIfNewStateEqualsOldState(); + } + + @Override + public boolean abortOperationIfNewStateEqualsOldState() { + return true; + } + + @Override + public String getOperationName() { + return null; // Default one is ok. + } + +} diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/SuspendPlanItemInstanceOperation.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/SuspendPlanItemInstanceOperation.java new file mode 100644 index 00000000000..6d7e60c685a --- /dev/null +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/agenda/operation/SuspendPlanItemInstanceOperation.java @@ -0,0 +1,79 @@ +/* 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.cmmn.engine.impl.agenda.operation; + +import java.util.List; + +import org.flowable.cmmn.api.runtime.PlanItemInstanceState; +import org.flowable.cmmn.engine.CmmnEngineConfiguration; +import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity; +import org.flowable.cmmn.engine.impl.util.CommandContextUtil; +import org.flowable.cmmn.model.PlanItemDefinition; +import org.flowable.cmmn.model.PlanItemTransition; +import org.flowable.cmmn.model.TimerEventListener; +import org.flowable.common.engine.api.FlowableIllegalStateException; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; + +public class SuspendPlanItemInstanceOperation extends AbstractChangePlanItemInstanceStateOperation { + + public SuspendPlanItemInstanceOperation(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) { + super(commandContext, planItemInstanceEntity); + } + + @Override + public String getNewState() { + return PlanItemInstanceState.SUSPENDED; + } + + @Override + public String getLifeCycleTransition() { + return PlanItemTransition.SUSPEND; + } + + @Override + protected void internalExecute() { + planItemInstanceEntity.setLastSuspendedTime(getCurrentTime(commandContext)); + + PlanItemDefinition planItemDefinition = planItemInstanceEntity.getPlanItem().getPlanItemDefinition(); + if (planItemDefinition instanceof TimerEventListener) { + CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext); + List timerJobs = cmmnEngineConfiguration.getJobServiceConfiguration().getTimerJobEntityManager().findJobsByScopeIdAndSubScopeId( + planItemInstanceEntity.getCaseInstanceId(), planItemInstanceEntity.getId()); + if (timerJobs != null && !timerJobs.isEmpty()) { + cmmnEngineConfiguration.getJobServiceConfiguration().getJobService().moveJobToSuspendedJob(timerJobs.get(0)); + } + } + + CommandContextUtil.getCmmnHistoryManager(commandContext).recordPlanItemInstanceSuspended(planItemInstanceEntity); + } + + @Override + public boolean isStateNotChanged(String oldState, String newState) { + if (oldState != null && oldState.equals(newState)) { + throw new FlowableIllegalStateException("plan item instance is already suspended"); + } + + return false; + } + + @Override + public boolean abortOperationIfNewStateEqualsOldState() { + return true; + } + + @Override + public String getOperationName() { + return "[Suspend plan item]"; + } +} diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/TimerEventListenerActivityBehaviour.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/TimerEventListenerActivityBehaviour.java index 7e02ee55e04..3455ba75b43 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/TimerEventListenerActivityBehaviour.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/behavior/impl/TimerEventListenerActivityBehaviour.java @@ -21,6 +21,7 @@ import org.apache.commons.lang3.StringUtils; import org.flowable.cmmn.api.delegate.DelegatePlanItemInstance; +import org.flowable.cmmn.api.runtime.PlanItemInstanceState; import org.flowable.cmmn.engine.CmmnEngineConfiguration; import org.flowable.cmmn.engine.impl.behavior.CmmnActivityBehavior; import org.flowable.cmmn.engine.impl.behavior.CoreCmmnActivityBehavior; @@ -45,6 +46,8 @@ import org.flowable.common.engine.impl.util.DateUtil; import org.flowable.job.service.JobServiceConfiguration; import org.flowable.job.service.impl.persistence.entity.JobEntity; +import org.flowable.job.service.impl.persistence.entity.SuspendedJobEntity; +import org.flowable.job.service.impl.persistence.entity.SuspendedJobEntityManager; import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; import org.flowable.job.service.impl.persistence.entity.TimerJobEntityManager; import org.joda.time.DateTime; @@ -73,7 +76,12 @@ public void onStateTransition(CommandContext commandContext, DelegatePlanItemIns || PlanItemTransition.TERMINATE.equals(transition) || PlanItemTransition.EXIT.equals(transition)) { - removeTimerJob(commandContext, (PlanItemInstanceEntity) planItemInstance); + if (PlanItemInstanceState.SUSPENDED.equals(planItemInstance.getState())) { + removeSuspendedJob(commandContext, (PlanItemInstanceEntity) planItemInstance); + + } else { + removeTimerJob(commandContext, (PlanItemInstanceEntity) planItemInstance); + } } } @@ -214,11 +222,20 @@ protected void scheduleTimerJob(CommandContext commandContext, PlanItemInstanceE protected void removeTimerJob(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) { TimerJobEntityManager timerJobEntityManager = CommandContextUtil.getCmmnEngineConfiguration(commandContext).getJobServiceConfiguration().getTimerJobEntityManager(); List timerJobsEntities = timerJobEntityManager - .findJobsByScopeIdAndSubScopeId(planItemInstanceEntity.getCaseInstanceId(), planItemInstanceEntity.getId()); + .findJobsByScopeIdAndSubScopeId(planItemInstanceEntity.getCaseInstanceId(), planItemInstanceEntity.getId()); for (TimerJobEntity timerJobEntity : timerJobsEntities) { timerJobEntityManager.delete(timerJobEntity); } } + + protected void removeSuspendedJob(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) { + SuspendedJobEntityManager suspendedJobEntityManager = CommandContextUtil.getCmmnEngineConfiguration(commandContext).getJobServiceConfiguration().getSuspendedJobEntityManager(); + List suspendedJobsEntities = suspendedJobEntityManager + .findJobsBySubScopeId(planItemInstanceEntity.getId()); + for (SuspendedJobEntity suspendedJobEntity : suspendedJobsEntities) { + suspendedJobEntityManager.delete(suspendedJobEntity); + } + } protected Object resolveTimerExpression(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) { ExpressionManager expressionManager = CommandContextUtil.getExpressionManager(commandContext); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/ActivateTaskCmd.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/ActivateTaskCmd.java index 323b1380780..1e78a778329 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/ActivateTaskCmd.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/ActivateTaskCmd.java @@ -13,8 +13,11 @@ package org.flowable.cmmn.engine.impl.cmd; import java.util.Date; +import java.util.List; +import org.flowable.cmmn.api.runtime.PlanItemInstanceState; import org.flowable.cmmn.engine.CmmnEngineConfiguration; +import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity; import org.flowable.cmmn.engine.impl.util.CommandContextUtil; import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.api.FlowableIllegalArgumentException; @@ -72,6 +75,14 @@ public Void execute(CommandContext commandContext) { } task.setSuspensionState(SuspensionState.ACTIVE.getStateCode()); + List planItemInstances = cmmnEngineConfiguration.getPlanItemInstanceEntityManager().findByReferenceId(task.getId()); + + if (planItemInstances != null && !planItemInstances.isEmpty()) { + planItemInstances.get(0).setState(PlanItemInstanceState.ACTIVE); + + cmmnEngineConfiguration.getCmmnHistoryManager().recordPlanItemInstanceUpdated(planItemInstances.get(0)); + } + HistoricTaskService historicTaskService = cmmnEngineConfiguration.getTaskServiceConfiguration().getHistoricTaskService(); historicTaskService.recordTaskInfoChange(task, updateTime, cmmnEngineConfiguration); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/ResumePlanItemInstanceCmd.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/ResumePlanItemInstanceCmd.java new file mode 100644 index 00000000000..8cb5dd8e4f7 --- /dev/null +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/ResumePlanItemInstanceCmd.java @@ -0,0 +1,30 @@ +/* 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.cmmn.engine.impl.cmd; + +import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity; +import org.flowable.cmmn.engine.impl.util.CommandContextUtil; +import org.flowable.common.engine.impl.interceptor.CommandContext; + +public class ResumePlanItemInstanceCmd extends AbstractNeedsPlanItemInstanceCmd { + + public ResumePlanItemInstanceCmd(String planItemInstanceId) { + super(planItemInstanceId); + } + + @Override + protected void internalExecute(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) { + CommandContextUtil.getAgenda(commandContext).planResumePlanItemInstanceOperation(planItemInstanceEntity); + } + +} diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/SuspendPlanItemInstanceCmd.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/SuspendPlanItemInstanceCmd.java new file mode 100644 index 00000000000..c4b15a321dc --- /dev/null +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/SuspendPlanItemInstanceCmd.java @@ -0,0 +1,30 @@ +/* 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.cmmn.engine.impl.cmd; + +import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity; +import org.flowable.cmmn.engine.impl.util.CommandContextUtil; +import org.flowable.common.engine.impl.interceptor.CommandContext; + +public class SuspendPlanItemInstanceCmd extends AbstractNeedsPlanItemInstanceCmd { + + public SuspendPlanItemInstanceCmd(String planItemInstanceId) { + super(planItemInstanceId); + } + + @Override + protected void internalExecute(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) { + CommandContextUtil.getAgenda(commandContext).planSuspendPlanItemInstanceOperation(planItemInstanceEntity); + } + +} diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/SuspendTaskCmd.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/SuspendTaskCmd.java index a3d196fbf5c..3b33d41c9d1 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/SuspendTaskCmd.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/cmd/SuspendTaskCmd.java @@ -13,8 +13,11 @@ package org.flowable.cmmn.engine.impl.cmd; import java.util.Date; +import java.util.List; +import org.flowable.cmmn.api.runtime.PlanItemInstanceState; import org.flowable.cmmn.engine.CmmnEngineConfiguration; +import org.flowable.cmmn.engine.impl.persistence.entity.PlanItemInstanceEntity; import org.flowable.cmmn.engine.impl.util.CommandContextUtil; import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.common.engine.impl.interceptor.CommandContext; @@ -44,6 +47,16 @@ protected Void execute(CommandContext commandContext, TaskEntity task) { task.setState(Task.SUSPENDED); task.setSuspensionState(SuspensionState.SUSPENDED.getStateCode()); + List planItemInstances = cmmnEngineConfiguration.getPlanItemInstanceEntityManager().findByReferenceId(task.getId()); + + if (planItemInstances != null && !planItemInstances.isEmpty()) { + PlanItemInstanceEntity planItemInstanceEntity = planItemInstances.get(0); + planItemInstanceEntity.setState(PlanItemInstanceState.SUSPENDED); + planItemInstanceEntity.setLastSuspendedTime(updateTime); + + cmmnEngineConfiguration.getCmmnHistoryManager().recordPlanItemInstanceSuspended(planItemInstanceEntity); + } + HistoricTaskService historicTaskService = cmmnEngineConfiguration.getTaskServiceConfiguration().getHistoricTaskService(); historicTaskService.recordTaskInfoChange(task, updateTime, cmmnEngineConfiguration); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/PlanItemInstanceEntityManager.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/PlanItemInstanceEntityManager.java index 6f98f1f2ec9..ff0a01c5c9f 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/PlanItemInstanceEntityManager.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/PlanItemInstanceEntityManager.java @@ -47,6 +47,8 @@ public interface PlanItemInstanceEntityManager extends EntityManager findByStagePlanItemInstanceId(String stagePlanItemInstanceId); List findByCaseInstanceIdAndPlanItemId(String caseInstanceId, String planItemId); + + List findByReferenceId(String referenceId); List findByStageInstanceIdAndPlanItemId(String stageInstanceId, String planItemId); diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/PlanItemInstanceEntityManagerImpl.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/PlanItemInstanceEntityManagerImpl.java index 8b73b68ee53..61080a4ab97 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/PlanItemInstanceEntityManagerImpl.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/PlanItemInstanceEntityManagerImpl.java @@ -53,6 +53,8 @@ import org.flowable.identitylink.service.impl.persistence.entity.IdentityLinkEntityManager; import org.flowable.job.service.impl.persistence.entity.ExternalWorkerJobEntity; import org.flowable.job.service.impl.persistence.entity.ExternalWorkerJobEntityManager; +import org.flowable.job.service.impl.persistence.entity.SuspendedJobEntity; +import org.flowable.job.service.impl.persistence.entity.SuspendedJobEntityManager; import org.flowable.job.service.impl.persistence.entity.TimerJobEntity; import org.flowable.job.service.impl.persistence.entity.TimerJobEntityManager; import org.flowable.task.service.impl.persistence.entity.TaskEntity; @@ -420,6 +422,11 @@ public List findByStagePlanItemInstanceId(String stagePl public List findByCaseInstanceIdAndPlanItemId(String caseInstanceId, String planitemId) { return dataManager.findByCaseInstanceIdAndPlanItemId(caseInstanceId, planitemId); } + + @Override + public List findByReferenceId(String referenceId) { + return dataManager.findByReferenceId(referenceId); + } @Override public List findByStageInstanceIdAndPlanItemId(String stageInstanceId, String planItemId) { @@ -529,11 +536,21 @@ public void delete(PlanItemInstanceEntity planItemInstanceEntity, boolean fireEv } if (planItemInstanceEntity.getPlanItemDefinitionType().equals(PlanItemDefinitionType.TIMER_EVENT_LISTENER)) { - TimerJobEntityManager timerJobEntityManager = engineConfiguration.getJobServiceConfiguration().getTimerJobEntityManager(); - List timerJobsEntities = timerJobEntityManager - .findJobsByScopeIdAndSubScopeId(planItemInstanceEntity.getCaseInstanceId(), planItemInstanceEntity.getId()); - for (TimerJobEntity timerJobEntity : timerJobsEntities) { - timerJobEntityManager.delete(timerJobEntity); + if (PlanItemInstanceState.SUSPENDED.equals(planItemInstanceEntity.getState())) { + SuspendedJobEntityManager suspendedJobEntityManager = engineConfiguration.getJobServiceConfiguration().getSuspendedJobEntityManager(); + List suspendedJobsEntities = suspendedJobEntityManager + .findJobsBySubScopeId(planItemInstanceEntity.getId()); + for (SuspendedJobEntity suspendedJobEntity : suspendedJobsEntities) { + suspendedJobEntityManager.delete(suspendedJobEntity); + } + + } else { + TimerJobEntityManager timerJobEntityManager = engineConfiguration.getJobServiceConfiguration().getTimerJobEntityManager(); + List timerJobsEntities = timerJobEntityManager + .findJobsByScopeIdAndSubScopeId(planItemInstanceEntity.getCaseInstanceId(), planItemInstanceEntity.getId()); + for (TimerJobEntity timerJobEntity : timerJobsEntities) { + timerJobEntityManager.delete(timerJobEntity); + } } } diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/PlanItemInstanceDataManager.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/PlanItemInstanceDataManager.java index 6d47f9ea3d3..0b74319dcb8 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/PlanItemInstanceDataManager.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/PlanItemInstanceDataManager.java @@ -30,6 +30,8 @@ public interface PlanItemInstanceDataManager extends DataManager findByCaseInstanceIdAndPlanItemId(String caseInstanceId, String planitemId); + List findByReferenceId(String referenceId); + List findByStageInstanceIdAndPlanItemId(String stageInstanceId, String planItemId); List findByCaseInstanceIdAndTypeAndState(String caseInstanceId, List planItemDefinitionTypes, diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/impl/MybatisPlanItemInstanceDataManagerImpl.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/impl/MybatisPlanItemInstanceDataManagerImpl.java index de7219d915f..7d14b830527 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/impl/MybatisPlanItemInstanceDataManagerImpl.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/persistence/entity/data/impl/MybatisPlanItemInstanceDataManagerImpl.java @@ -43,6 +43,9 @@ public class MybatisPlanItemInstanceDataManagerImpl extends AbstractCmmnDataMana protected PlanItemInstanceByCaseInstanceIdAndTypeAndStateCachedEntityMatcher planItemInstanceByCaseInstanceIdAndTypeAndStateCachedEntityMatcher = new PlanItemInstanceByCaseInstanceIdAndTypeAndStateCachedEntityMatcher(); + + protected PlanItemInstanceByReferenceIdCachedEntityMatcher planItemInstanceByReferenceIdCachedEntityMatcher = + new PlanItemInstanceByReferenceIdCachedEntityMatcher(); protected PlanItemInstanceByStagePlanItemInstanceIdCachedEntityMatcher planItemInstanceByStagePlanItemInstanceIdCachedEntityMatcher = new PlanItemInstanceByStagePlanItemInstanceIdCachedEntityMatcher(); @@ -101,6 +104,11 @@ public List findByCaseInstanceIdAndPlanItemId(String cas params.put("planItemId", planitemId); return getList("selectPlanItemInstancesByCaseInstanceIdAndPlanItemId", params, planItemInstanceByCaseInstanceIdAndPlanItemIdCachedEntityMatcher); } + + @Override + public List findByReferenceId(String referenceId) { + return getList("selectPlanItemInstancesByReferenceId", referenceId, planItemInstanceByReferenceIdCachedEntityMatcher, true); + } @Override public List findByStageInstanceIdAndPlanItemId(String stageInstanceId, String planItemId) { @@ -172,6 +180,16 @@ public boolean isRetained(PlanItemInstanceEntity entity, Object param) { } } + + public static class PlanItemInstanceByReferenceIdCachedEntityMatcher extends CachedEntityMatcherAdapter { + + @Override + public boolean isRetained(PlanItemInstanceEntity entity, Object param) { + String referenceId = (String) param; + return referenceId.equals(entity.getReferenceId()); + } + + } public static class PlanItemInstanceByCaseInstanceIdAndPlanItemIdCachedEntityMatcher extends CachedEntityMatcherAdapter { diff --git a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceTransitionBuilderImpl.java b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceTransitionBuilderImpl.java index b4d86587eb7..e57d900bed6 100644 --- a/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceTransitionBuilderImpl.java +++ b/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/runtime/PlanItemInstanceTransitionBuilderImpl.java @@ -19,7 +19,9 @@ import org.flowable.cmmn.engine.impl.cmd.CompleteStagePlanItemInstanceCmd; import org.flowable.cmmn.engine.impl.cmd.DisablePlanItemInstanceCmd; import org.flowable.cmmn.engine.impl.cmd.EnablePlanItemInstanceCmd; +import org.flowable.cmmn.engine.impl.cmd.ResumePlanItemInstanceCmd; import org.flowable.cmmn.engine.impl.cmd.StartPlanItemInstanceCmd; +import org.flowable.cmmn.engine.impl.cmd.SuspendPlanItemInstanceCmd; import org.flowable.cmmn.engine.impl.cmd.TerminatePlanItemInstanceCmd; import org.flowable.cmmn.engine.impl.cmd.TriggerPlanItemInstanceCmd; import org.flowable.common.engine.api.FlowableIllegalArgumentException; @@ -195,6 +197,18 @@ public void start() { formInfo, localVariables, transientVariables, childTaskVariables, childTaskFormVariables, childTaskFormOutcome, childTaskFormInfo)); } + + @Override + public void suspend() { + validateChildTaskVariablesNotSet(); + commandExecutor.execute(new SuspendPlanItemInstanceCmd(planItemInstanceId)); + } + + @Override + public void resume() { + validateChildTaskVariablesNotSet(); + commandExecutor.execute(new ResumePlanItemInstanceCmd(planItemInstanceId)); + } @Override public void terminate() { diff --git a/modules/flowable-cmmn-engine/src/main/resources/org/flowable/cmmn/db/mapping/entity/PlanItemInstance.xml b/modules/flowable-cmmn-engine/src/main/resources/org/flowable/cmmn/db/mapping/entity/PlanItemInstance.xml index 5b8fafda665..46309f27c04 100644 --- a/modules/flowable-cmmn-engine/src/main/resources/org/flowable/cmmn/db/mapping/entity/PlanItemInstance.xml +++ b/modules/flowable-cmmn-engine/src/main/resources/org/flowable/cmmn/db/mapping/entity/PlanItemInstance.xml @@ -358,11 +358,16 @@ select * from ${prefix}ACT_CMMN_RU_PLAN_ITEM_INST RES where CASE_INST_ID_ = #{parameter.caseInstanceId, jdbcType=VARCHAR} and ELEMENT_ID_ = #{parameter.planItemId, jdbcType=VARCHAR} + + - + + +