All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.camunda.operate.webapp.zeebe.operation.process.modify.SingleStepModifyProcessInstanceHandler Maven / Gradle / Ivy

/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
 * one or more contributor license agreements. See the NOTICE file distributed
 * with this work for additional information regarding copyright ownership.
 * Licensed under the Camunda License 1.0. You may not use this file
 * except in compliance with the Camunda License 1.0.
 */
package io.camunda.operate.webapp.zeebe.operation.process.modify;

import static io.camunda.operate.webapp.rest.dto.operation.ModifyProcessInstanceRequestDto.Modification;
import static io.camunda.operate.webapp.rest.dto.operation.ModifyProcessInstanceRequestDto.Modification.Type.*;
import static java.util.function.Predicate.not;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.camunda.operate.entities.OperationEntity;
import io.camunda.operate.entities.OperationType;
import io.camunda.operate.exceptions.PersistenceException;
import io.camunda.operate.util.OperationsManager;
import io.camunda.operate.webapp.rest.dto.operation.ModifyProcessInstanceRequestDto;
import io.camunda.operate.webapp.zeebe.operation.AbstractOperationHandler;
import io.camunda.operate.webapp.zeebe.operation.ModifyProcessZeebeWrapper;
import io.camunda.zeebe.client.ZeebeClient;
import io.camunda.zeebe.client.api.command.ModifyProcessInstanceCommandStep1;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

// Modify Process Instance Implementation to execute all given modifications in one Zeebe
// 'transaction'
// So for one operation we have only one 'zeebeClient.send().join()'
@Component
public class SingleStepModifyProcessInstanceHandler extends AbstractOperationHandler
    implements ModifyProcessInstanceHandler {

  private static final Logger LOGGER =
      LoggerFactory.getLogger(SingleStepModifyProcessInstanceHandler.class);

  @Autowired
  @Qualifier("operateObjectMapper")
  private ObjectMapper objectMapper;

  @Autowired private OperationsManager operationsManager;
  @Autowired private MoveTokenHandler moveTokenHandler;
  @Autowired private AddTokenHandler addTokenHandler;
  @Autowired private CancelTokenHandler cancelTokenHandler;
  @Autowired private ModifyProcessZeebeWrapper modifyProcessZeebeWrapper;

  @Override
  public void handleWithException(final OperationEntity operation) throws Exception {
    // Create request from serialized instructions
    final ModifyProcessInstanceRequestDto modifyProcessInstanceRequest =
        objectMapper.readValue(
            operation.getModifyInstructions(), ModifyProcessInstanceRequestDto.class);
    // Process variable modifications
    modifyVariables(modifyProcessInstanceRequest, operation);

    // Process token (non-variable) modifications
    final ModifyProcessInstanceCommandStep1.ModifyProcessInstanceCommandStep2 lastStep =
        processTokenModifications(modifyProcessInstanceRequest, operation);

    modifyProcessZeebeWrapper.sendModificationsToZeebe(lastStep);
    markAsSent(operation);
    operationsManager.completeOperation(operation, false);
  }

  @Override
  public Set getTypes() {
    return Set.of(OperationType.MODIFY_PROCESS_INSTANCE);
  }

  // Needed for tests
  @Override
  public void setZeebeClient(final ZeebeClient zeebeClient) {
    this.zeebeClient = zeebeClient;
    modifyProcessZeebeWrapper.setZeebeClient(zeebeClient);
  }

  private ModifyProcessInstanceCommandStep1.ModifyProcessInstanceCommandStep2
      processTokenModifications(
          final ModifyProcessInstanceRequestDto modifyProcessInstanceRequest,
          final OperationEntity operation)
          throws PersistenceException {
    ModifyProcessInstanceCommandStep1.ModifyProcessInstanceCommandStep2 lastStep = null;

    final Long processInstanceKey =
        Long.parseLong(modifyProcessInstanceRequest.getProcessInstanceKey());
    ModifyProcessInstanceCommandStep1 currentStep =
        modifyProcessZeebeWrapper.newModifyProcessInstanceCommand(processInstanceKey);
    final List tokenModifications =
        getTokenModifications(modifyProcessInstanceRequest.getModifications());

    for (final var iter = tokenModifications.iterator(); iter.hasNext(); ) {
      final Modification modification = iter.next();
      ModifyProcessInstanceCommandStep1.ModifyProcessInstanceCommandStep2 nextStep = null;
      switch (modification.getModification()) {
        case ADD_TOKEN:
          nextStep = addTokenHandler.addToken(currentStep, modification);
          break;
        case CANCEL_TOKEN:
          nextStep = cancelTokenHandler.cancelToken(currentStep, processInstanceKey, modification);
          break;
        case MOVE_TOKEN:
          nextStep = moveTokenHandler.moveToken(currentStep, processInstanceKey, modification);
          break;
        default:
          LOGGER.warn(
              "SingleStepModifyProcessInstanceHandler encountered a modification type that should have been filtered out: {}",
              modification.getModification());
          break;
      }

      // Append 'and' if there is at least one more operation to process
      if (nextStep != null) {
        lastStep = nextStep;
        if (iter.hasNext()) {
          currentStep = nextStep.and();
        }
      }

      // Always update the finished metrics
      operationsManager.updateFinishedInBatchOperation(operation.getBatchOperationId());
    }

    return lastStep;
  }

  private void updateFinishedInBatchOperation(final OperationEntity operation)
      throws PersistenceException {
    operationsManager.updateFinishedInBatchOperation(operation.getBatchOperationId());
  }

  private void modifyVariables(
      final ModifyProcessInstanceRequestDto modifyProcessInstanceRequest,
      final OperationEntity operation)
      throws PersistenceException {
    final Long processInstanceKey =
        Long.parseLong(modifyProcessInstanceRequest.getProcessInstanceKey());
    final List modifications =
        getVariableModifications(modifyProcessInstanceRequest.getModifications());
    for (final Modification modification : modifications) {
      final Long scopeKey =
          modification.getScopeKey() == null ? processInstanceKey : modification.getScopeKey();
      modifyProcessZeebeWrapper.setVariablesInZeebe(scopeKey, modification.getVariables());
      updateFinishedInBatchOperation(operation);
    }
  }

  private List getVariableModifications(final List modifications) {
    return modifications.stream().filter(this::isVariableModification).collect(Collectors.toList());
  }

  private List getTokenModifications(final List modifications) {
    return modifications.stream()
        .filter(not(this::isVariableModification))
        .collect(Collectors.toList());
  }

  private boolean isVariableModification(final Modification modification) {
    return modification.getModification().equals(ADD_VARIABLE)
        || modification.getModification().equals(EDIT_VARIABLE);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy