Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change state termination #3943

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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 @@ -34,9 +34,10 @@ public ChangeActivityStateCmd(ChangeActivityStateBuilderImpl changeActivityState
@Override
public Void execute(CommandContext commandContext) {
if (changeActivityStateBuilder.getMoveExecutionIdList().isEmpty() && changeActivityStateBuilder.getMoveActivityIdList().isEmpty()
&& changeActivityStateBuilder.getEnableActivityIdList().isEmpty()) {
&& changeActivityStateBuilder.getEnableActivityIdList().isEmpty() && changeActivityStateBuilder.getTerminateActivityIdList().isEmpty()
&& changeActivityStateBuilder.getTerminateExecutionIdList().isEmpty()) {

throw new FlowableIllegalArgumentException("No move execution or activity ids or enable activity ids provided");
throw new FlowableIllegalArgumentException("No move, enable or terminate activity ids provided");

} else if ((!changeActivityStateBuilder.getMoveActivityIdList().isEmpty() || !changeActivityStateBuilder.getEnableActivityIdList().isEmpty()) && changeActivityStateBuilder.getProcessInstanceId() == null) {
throw new FlowableIllegalArgumentException("Process instance id is required");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@
import org.flowable.engine.impl.runtime.EnableActivityIdContainer;
import org.flowable.engine.impl.runtime.MoveActivityIdContainer;
import org.flowable.engine.impl.runtime.MoveExecutionIdContainer;
import org.flowable.engine.impl.runtime.TerminateActivityContainer;
import org.flowable.engine.impl.runtime.TerminateExecutionContainer;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.CountingEntityUtil;
import org.flowable.engine.impl.util.EntityLinkUtil;
Expand Down Expand Up @@ -248,7 +250,66 @@ public List<MoveExecutionEntityContainer> resolveMoveExecutionEntityContainers(C

return moveExecutionEntityContainerList;
}


public List<TerminateActivityContainer> resolveTerminateActivityContainers(ChangeActivityStateBuilderImpl changeActivityStateBuilder, CommandContext commandContext) {
List<TerminateActivityContainer> terminateActivityContainerList = new ArrayList<>();
// if (!changeActivityStateBuilder.getTerminateActivityIdList().isEmpty()) {
// for (TerminateActivityContainer terminateActivityIdContainer : changeActivityStateBuilder.getTerminateActivityIdList()) {
// TerminateActivityContainer terminateActivityContainer = new TerminateActivityContainer(terminateActivityIdContainer.getActivityIds());
// terminateActivityContainerList.add(terminateActivityContainer);
// resolveActiveExecution(executionId, commandContext)
// terminateActivityContainer.setExecution(terminateActivityIdContainer.getExecution());
// }
// }

return terminateActivityContainerList;
}

public List<TerminateExecutionContainer> resolveTerminateExecutionContainers(ChangeActivityStateBuilderImpl changeActivityStateBuilder, CommandContext commandContext) {
List<TerminateExecutionContainer> terminateExecutionContainerList = new ArrayList<>();
if (!changeActivityStateBuilder.getTerminateExecutionIdList().isEmpty()) {
for (TerminateExecutionContainer terminateExecutionIdContainer : changeActivityStateBuilder.getTerminateExecutionIdList()) {
TerminateExecutionContainer terminateExecutionContainer = new TerminateExecutionContainer(terminateExecutionIdContainer.getExecutionIds());
for (String executionId : terminateExecutionIdContainer.getExecutionIds()) {
terminateExecutionContainer.getExecutions().add(resolveActiveExecution(executionId, commandContext));
}
terminateExecutionContainerList.add(terminateExecutionContainer);
}
}

return terminateExecutionContainerList;
}

public List<TerminateExecutionContainer> resolveExecutionsFromTerminateActivitiesContainers(ChangeActivityStateBuilderImpl changeActivityStateBuilder, CommandContext commandContext) {
List<TerminateExecutionContainer> terminateExecutionContainerList = new ArrayList<>();
if(changeActivityStateBuilder.getTerminateActivityIdList().isEmpty()) {
return terminateExecutionContainerList;
}

String processInstanceId = changeActivityStateBuilder.getProcessInstanceId();
ExecutionEntity execution = resolveActiveExecution(processInstanceId, commandContext);
ExecutionEntity finalExecution;
if (!changeActivityStateBuilder.getTerminateActivityIdList().isEmpty()) {
for (TerminateActivityContainer terminateActivityIdContainer : changeActivityStateBuilder.getTerminateActivityIdList()) {
if(terminateActivityIdContainer.isTerminateInParentProcess()) {
ExecutionEntity processInstanceExecution = execution.getProcessInstance();
finalExecution = processInstanceExecution.getSuperExecution();
if (finalExecution == null) {
throw new FlowableException("No parent process found for execution with activity id " + execution.getCurrentActivityId());
}
}

TerminateExecutionContainer terminateExecutionContainer = new TerminateExecutionContainer();
for (String activityId : terminateActivityIdContainer.getActivityIds()) {
terminateExecutionContainer.getExecutions().addAll(resolveActiveExecutions(processInstanceId, activityId, commandContext));
}
terminateExecutionContainerList.add(terminateExecutionContainer);
}
}

return terminateExecutionContainerList;
}

public List<EnableActivityContainer> resolveEnableActivityContainers(ChangeActivityStateBuilderImpl changeActivityStateBuilder) {
List<EnableActivityContainer> enableActivityContainerList = new ArrayList<>();
if (!changeActivityStateBuilder.getEnableActivityIdList().isEmpty()) {
Expand Down Expand Up @@ -651,6 +712,21 @@ protected void doMoveExecutionState(ProcessInstanceChangeState processInstanceCh
}
}
}


// Terminate executions
for(TerminateExecutionContainer terminateExecutionContainer : processInstanceChangeState.getTerminateExecutionContainers()) {
if (terminateExecutionContainer.getExecutions() != null && !terminateExecutionContainer.getExecutions().isEmpty()) {
for (ExecutionEntity execution : terminateExecutionContainer.getExecutions()) {
if(execution == null) {
throw new FlowableException("Execution cannot be terminate because it is null");
}
executionEntityManager.deleteChildExecutions(execution, Collections.emptyList(), null, "Terminate execution " + execution.getId() + " with activity id " + execution.getActivityId(), true, null);
executionEntityManager.deleteExecutionAndRelatedData(execution, "Terminate execution " + execution.getId() + " with activity id " + execution.getActivityId(), false, false, true, execution.getCurrentFlowElement());
}
}
}

}

protected void processPendingEventSubProcessesStartEvents(ProcessInstanceChangeState processInstanceChangeState, CommandContext commandContext) {
Expand All @@ -673,6 +749,7 @@ protected void safeDeleteSubProcessInstance(String processInstanceId, List<Execu

//Confirm that all the subProcessExecutions are in the executionsPool
List<ExecutionEntity> subProcessExecutions = executionEntityManager.findChildExecutionsByProcessInstanceId(processInstanceId);
subProcessExecutions = subProcessExecutions.stream().filter(e -> !(e.getCurrentFlowElement() instanceof BoundaryEvent)).collect(Collectors.toList());
HashSet<String> executionIdsToMove = executionsPool.stream().map(ExecutionEntity::getId).collect(Collectors.toCollection(HashSet::new));
Optional<ExecutionEntity> notIncludedExecution = subProcessExecutions.stream().filter(e -> !executionIdsToMove.contains(e.getId())).findAny();
if (notIncludedExecution.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

package org.flowable.engine.impl.dynamic;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand All @@ -24,6 +25,7 @@
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.runtime.ChangeActivityStateBuilderImpl;
import org.flowable.engine.impl.runtime.TerminateExecutionContainer;
import org.flowable.engine.impl.util.CommandContextUtil;

/**
Expand All @@ -47,14 +49,19 @@ public void moveExecutionState(ChangeActivityStateBuilderImpl changeActivityStat
} else {
processInstanceId = changeActivityStateBuilder.getProcessInstanceId();
}


List<TerminateExecutionContainer> terminateExecutionContainerList = new ArrayList<>();
terminateExecutionContainerList.addAll(resolveTerminateExecutionContainers(changeActivityStateBuilder, commandContext));
terminateExecutionContainerList.addAll(resolveExecutionsFromTerminateActivitiesContainers(changeActivityStateBuilder, commandContext));

ProcessInstanceChangeState processInstanceChangeState = new ProcessInstanceChangeState()
.setProcessInstanceId(processInstanceId)
.setMoveExecutionEntityContainers(moveExecutionEntityContainerList)
.setEnableActivityContainers(enableActivityContainerList)
.setTerminateExecutionContainers(terminateExecutionContainerList)
.setLocalVariables(changeActivityStateBuilder.getLocalVariables())
.setProcessInstanceVariables(changeActivityStateBuilder.getProcessInstanceVariables());

doMoveExecutionState(processInstanceChangeState, commandContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.flowable.bpmn.model.StartEvent;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.runtime.TerminateExecutionContainer;
import org.flowable.engine.repository.ProcessDefinition;

/**
Expand All @@ -33,6 +34,7 @@ public class ProcessInstanceChangeState {
protected Map<String, Map<String, Object>> localVariables = new HashMap<>();
protected Map<String, List<ExecutionEntity>> processInstanceActiveEmbeddedExecutions;
protected List<MoveExecutionEntityContainer> moveExecutionEntityContainers;
protected List<TerminateExecutionContainer> terminateExecutionContainers;
protected List<EnableActivityContainer> enableActivityContainers;
protected HashMap<String, ExecutionEntity> createdEmbeddedSubProcess = new HashMap<>();
protected HashMap<String, ExecutionEntity> createdMultiInstanceRootExecution = new HashMap<>();
Expand Down Expand Up @@ -99,6 +101,16 @@ public ProcessInstanceChangeState setMoveExecutionEntityContainers(List<MoveExec
return this;
}

public List<TerminateExecutionContainer> getTerminateExecutionContainers() {
return terminateExecutionContainers;
}

public ProcessInstanceChangeState setTerminateExecutionContainers(List<TerminateExecutionContainer> terminateExecutionContainerList) {
this.terminateExecutionContainers = terminateExecutionContainerList;
return this;
}


public HashMap<String, ExecutionEntity> getCreatedEmbeddedSubProcesses() {
return createdEmbeddedSubProcess;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public class ChangeActivityStateBuilderImpl implements ChangeActivityStateBuilde
protected List<MoveExecutionIdContainer> moveExecutionIdList = new ArrayList<>();
protected List<MoveActivityIdContainer> moveActivityIdList = new ArrayList<>();
protected List<EnableActivityIdContainer> enableActivityIdList = new ArrayList<>();
protected List<TerminateActivityContainer> terminateActivityContainers = new ArrayList<>();
protected List<TerminateExecutionContainer> terminateExecutionContainers = new ArrayList<>();
protected Map<String, Object> processVariables = new HashMap<>();
protected Map<String, Map<String, Object>> localVariables = new HashMap<>();

Expand Down Expand Up @@ -171,14 +173,61 @@ public ChangeActivityStateBuilder moveSingleActivityIdToSubProcessInstanceActivi
moveActivityIdList.add(moveActivityIdsContainer);
return this;
}

@Override
public ChangeActivityStateBuilder enableEventSubProcessStartEvent(String eventSubProcessStartEventId) {
EnableActivityIdContainer enableActivityIdContainer = new EnableActivityIdContainer(eventSubProcessStartEventId);
enableActivityIdList.add(enableActivityIdContainer);
return this;
}

@Override
public ChangeActivityStateBuilder terminateActivity(String activityId) {
TerminateActivityContainer terminateActivityContainer = new TerminateActivityContainer(activityId);
terminateActivityContainers.add(terminateActivityContainer);
return this;
}

@Override
public ChangeActivityStateBuilder terminateActivities(List<String> activityIds) {
TerminateActivityContainer terminateActivityContainer = new TerminateActivityContainer(activityIds);
terminateActivityContainers.add(terminateActivityContainer);
return this;
}

@Override
public ChangeActivityStateBuilder terminateParentProcessInstanceActivity(String activityId) {
TerminateActivityContainer terminateActivityContainer = new TerminateActivityContainer(activityId);
terminateActivityContainer.setTerminateInParentProcess(true);
terminateActivityContainers.add(terminateActivityContainer);
return this;
}


@Override
public ChangeActivityStateBuilder terminateParentProcessInstanceActivities(List<String> activityIds) {
TerminateActivityContainer terminateActivityContainer = new TerminateActivityContainer(activityIds);
terminateActivityContainer.setTerminateInParentProcess(true);
terminateActivityContainers.add(terminateActivityContainer);
return this;
}



@Override
public ChangeActivityStateBuilder terminateExecution(String executionId) {
TerminateExecutionContainer terminateExecutionContainer = new TerminateExecutionContainer(executionId);
terminateExecutionContainers.add(terminateExecutionContainer);
return this;
}

@Override
public ChangeActivityStateBuilder terminateExecutions(List<String> executionIds) {
TerminateExecutionContainer terminateExecutionContainer = new TerminateExecutionContainer(executionIds);
terminateExecutionContainers.add(terminateExecutionContainer);
return this;
}

@Override
public ChangeActivityStateBuilder processVariable(String processVariableName, Object processVariableValue) {
if (this.processVariables == null) {
Expand Down Expand Up @@ -250,6 +299,14 @@ public List<EnableActivityIdContainer> getEnableActivityIdList() {
return enableActivityIdList;
}

public List<TerminateActivityContainer> getTerminateActivityIdList() {
return terminateActivityContainers;
}

public List<TerminateExecutionContainer> getTerminateExecutionIdList() {
return terminateExecutionContainers;
}

public Map<String, Object> getProcessInstanceVariables() {
return processVariables;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* 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.engine.impl.runtime;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
* @author Matthias Stöckli
*/
public class TerminateActivityContainer {

protected List<String> activityIds;

protected boolean terminateInParentProcess;

public TerminateActivityContainer(String singleActivityId) {
this.activityIds = Collections.singletonList(singleActivityId);
}

public TerminateActivityContainer(List<String> activityIds) {
this.activityIds = activityIds;
}

public List<String> getActivityIds() {
return Optional.ofNullable(activityIds).orElse(Collections.emptyList());
}

public boolean isTerminateInParentProcess() {
return terminateInParentProcess;
}

public void setTerminateInParentProcess(boolean terminateInParentProcess) {
this.terminateInParentProcess = terminateInParentProcess;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* 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.engine.impl.runtime;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.flowable.engine.impl.persistence.entity.ExecutionEntity;

/**
* @author Matthias Stöckli
*/
public class TerminateExecutionContainer {

protected List<String> executionIds = new ArrayList<>();
protected List<ExecutionEntity> executions = new ArrayList<>();

public TerminateExecutionContainer() {
}

public TerminateExecutionContainer(String singleExecutionId) {
this.executionIds = Collections.singletonList(singleExecutionId);
}

public TerminateExecutionContainer(List<String> executionIds) {
this.executionIds = executionIds;
}

public List<String> getExecutionIds() {
return Optional.ofNullable(executionIds).orElse(Collections.emptyList());
}


public List<ExecutionEntity> getExecutions() {
return executions;
}
}
Loading
Loading