content: /*
   * Copyright 2010-2025 Hyland Software, Inc. and its affiliates.
   *
   * 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.activiti.engine.impl.agenda;
  
  import java.util.Collection;
  import org.activiti.engine.ActivitiException;
  import org.activiti.engine.impl.interceptor.CommandContext;
  import org.activiti.engine.impl.persistence.entity.DeadLetterJobEntity;
  import org.activiti.engine.impl.persistence.entity.DeadLetterJobEntityManager;
  import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
  import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
  import org.activiti.engine.impl.persistence.entity.JobEntity;
  import org.activiti.engine.impl.persistence.entity.JobEntityManager;
  import org.activiti.engine.impl.persistence.entity.SuspendedJobEntity;
  import org.activiti.engine.impl.persistence.entity.SuspendedJobEntityManager;
  import org.activiti.engine.impl.persistence.entity.TaskEntity;
  import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
  import org.activiti.engine.impl.persistence.entity.TimerJobEntity;
  import org.activiti.engine.impl.persistence.entity.TimerJobEntityManager;
  import org.activiti.engine.impl.persistence.entity.VariableInstanceEntity;
  import org.activiti.engine.impl.persistence.entity.VariableInstanceEntityManager;
  
  /**
   * Destroys a scope (for example a subprocess): this means that all child executions,
   * tasks, jobs, variables, etc within that scope are deleted.
   * <p>
   * The typical example is an interrupting boundary event that is on the boundary
   * of a subprocess and is triggered. At that point, everything within the subprocess would
   * need to be destroyed.
   */
  public class DestroyScopeOperation extends AbstractOperation {
  
      public DestroyScopeOperation(CommandContext commandContext, ExecutionEntity execution) {
          super(commandContext, execution);
      }
  
      @Override
      public void run() {
          // Find the actual scope that needs to be destroyed.
          // This could be the incoming execution, or the first parent execution where isScope = true
  
          // Find parent scope execution
          ExecutionEntity scopeExecution = execution.isScope() ? execution : findFirstParentScopeExecution(execution);
  
          if (scopeExecution == null) {
              throw new ActivitiException("Programmatic error: no parent scope execution found for boundary event");
          }
  
          ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
          deleteAllChildExecutions(executionEntityManager, scopeExecution);
  
          // Delete all scope tasks
          TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
          deleteAllScopeTasks(scopeExecution, taskEntityManager);
  
          // Delete all scope jobs
          TimerJobEntityManager timerJobEntityManager = commandContext.getTimerJobEntityManager();
          deleteAllScopeJobs(scopeExecution, timerJobEntityManager);
  
          // Remove variables associated with this scope
          VariableInstanceEntityManager variableInstanceEntityManager = commandContext.getVariableInstanceEntityManager();
          removeAllVariablesFromScope(scopeExecution, variableInstanceEntityManager);
  
          commandContext.getHistoryManager().recordActivityEnd(scopeExecution, scopeExecution.getDeleteReason());
          executionEntityManager.delete(scopeExecution);
      }
  
      private void removeAllVariablesFromScope(
          ExecutionEntity scopeExecution,
          VariableInstanceEntityManager variableInstanceEntityManager
      ) {
          Collection<VariableInstanceEntity> variablesForExecution =
              variableInstanceEntityManager.findVariableInstancesByExecutionId(scopeExecution.getId());
          for (VariableInstanceEntity variable : variablesForExecution) {
              variableInstanceEntityManager.delete(variable);
          }
      }
  
      private void deleteAllScopeJobs(ExecutionEntity scopeExecution, TimerJobEntityManager timerJobEntityManager) {
          Collection<TimerJobEntity> timerJobsForExecution = timerJobEntityManager.findJobsByExecutionId(
              scopeExecution.getId()
          );
          for (TimerJobEntity job : timerJobsForExecution) {
              timerJobEntityManager.delete(job);
          }
  
          JobEntityManager jobEntityManager = commandContext.getJobEntityManager();
          Collection<JobEntity> jobsForExecution = jobEntityManager.findJobsByExecutionId(scopeExecution.getId());
          for (JobEntity job : jobsForExecution) {
              jobEntityManager.delete(job);
          }
  
          SuspendedJobEntityManager suspendedJobEntityManager = commandContext.getSuspendedJobEntityManager();
          Collection<SuspendedJobEntity> suspendedJobsForExecution = suspendedJobEntityManager.findJobsByExecutionId(
              scopeExecution.getId()
          );
          for (SuspendedJobEntity job : suspendedJobsForExecution) {
              suspendedJobEntityManager.delete(job);
          }
  
          DeadLetterJobEntityManager deadLetterJobEntityManager = commandContext.getDeadLetterJobEntityManager();
          Collection<DeadLetterJobEntity> deadLetterJobsForExecution = deadLetterJobEntityManager.findJobsByExecutionId(
              scopeExecution.getId()
          );
          for (DeadLetterJobEntity job : deadLetterJobsForExecution) {
              deadLetterJobEntityManager.delete(job);
          }
      }
  
      private void deleteAllScopeTasks(ExecutionEntity scopeExecution, TaskEntityManager taskEntityManager) {
          Collection<TaskEntity> tasksForExecution = taskEntityManager.findTasksByExecutionId(scopeExecution.getId());
          for (TaskEntity taskEntity : tasksForExecution) {
              taskEntityManager.deleteTask(taskEntity, execution.getDeleteReason(), false, false);
          }
      }
  
      private ExecutionEntityManager deleteAllChildExecutions(
          ExecutionEntityManager executionEntityManager,
          ExecutionEntity scopeExecution
      ) {
          // Delete all child executions
          Collection<ExecutionEntity> childExecutions = executionEntityManager.findChildExecutionsByParentExecutionId(
              scopeExecution.getId()
          );
          for (ExecutionEntity childExecution : childExecutions) {
              executionEntityManager.deleteExecutionAndRelatedData(childExecution, execution.getDeleteReason());
          }
          return executionEntityManager;
      }
  }
  