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 org.activiti.bpmn.model.FlowElement;
  import org.activiti.bpmn.model.HasExecutionListeners;
  import org.activiti.engine.Agenda;
  import org.activiti.engine.delegate.ExecutionListener;
  import org.activiti.engine.impl.interceptor.Command;
  import org.activiti.engine.impl.interceptor.CommandContext;
  import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
  import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
  import org.activiti.engine.impl.util.ProcessDefinitionUtil;
  
  /**
   * Abstract superclass for all operation interfaces (which are {@link Runnable} instances),
   * exposing some shared helper methods and member fields to subclasses.
   *
   * An operations is a {@link Runnable} instance that is put on the {@link Agenda} during
   * the execution of a {@link Command}.
   *
  
   */
  public abstract class AbstractOperation implements Runnable {
  
      protected CommandContext commandContext;
      protected Agenda agenda;
      protected ExecutionEntity execution;
  
      public AbstractOperation() {}
  
      public AbstractOperation(CommandContext commandContext, ExecutionEntity execution) {
          this.commandContext = commandContext;
          this.execution = execution;
          this.agenda = commandContext.getAgenda();
      }
  
      /**
       * Helper method to match the activityId of an execution with a FlowElement of the process definition referenced by the execution.
       */
      protected FlowElement getCurrentFlowElement(final ExecutionEntity execution) {
          if (execution.getCurrentFlowElement() != null) {
              return execution.getCurrentFlowElement();
          } else if (execution.getCurrentActivityId() != null) {
              String processDefinitionId = execution.getProcessDefinitionId();
              org.activiti.bpmn.model.Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
              String activityId = execution.getCurrentActivityId();
              FlowElement currentFlowElement = process.getFlowElement(activityId, true);
              return currentFlowElement;
          }
          return null;
      }
  
      /**
       * Executes the execution listeners defined on the given element, with the given event type.
       * Uses the {@link #execution} of this operation instance as argument for the execution listener.
       */
      protected void executeExecutionListeners(HasExecutionListeners elementWithExecutionListeners, String eventType) {
          executeExecutionListeners(elementWithExecutionListeners, execution, eventType);
      }
  
      /**
       * Executes the execution listeners defined on the given element, with the given event type,
       * and passing the provided execution to the {@link ExecutionListener} instances.
       */
      protected void executeExecutionListeners(
          HasExecutionListeners elementWithExecutionListeners,
          ExecutionEntity executionEntity,
          String eventType
      ) {
          commandContext
              .getProcessEngineConfiguration()
              .getListenerNotificationHelper()
              .executeExecutionListeners(elementWithExecutionListeners, executionEntity, eventType);
      }
  
      /**
       * Returns the first parent execution of the provided execution that is a scope.
       */
      protected ExecutionEntity findFirstParentScopeExecution(ExecutionEntity executionEntity) {
          ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
          ExecutionEntity parentScopeExecution = null;
          ExecutionEntity currentlyExaminedExecution = executionEntityManager.findById(executionEntity.getParentId());
          while (currentlyExaminedExecution != null && parentScopeExecution == null) {
              if (currentlyExaminedExecution.isScope()) {
                  parentScopeExecution = currentlyExaminedExecution;
              } else {
                  currentlyExaminedExecution = executionEntityManager.findById(currentlyExaminedExecution.getParentId());
              }
          }
          return parentScopeExecution;
      }
  
      public CommandContext getCommandContext() {
          return commandContext;
      }
  
      public void setCommandContext(CommandContext commandContext) {
          this.commandContext = commandContext;
      }
  
      public Agenda getAgenda() {
          return agenda;
      }
  
      public void setAgenda(DefaultActivitiEngineAgenda agenda) {
          this.agenda = agenda;
      }
  
      public ExecutionEntity getExecution() {
          return execution;
      }
  
      public void setExecution(ExecutionEntity execution) {
          this.execution = execution;
      }
  }
  