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

io.camunda.exporter.handlers.UserTaskHandler Maven / Gradle / Ivy

There is a newer version: 8.7.0-alpha2
Show newest version
/*
 * 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.exporter.handlers;

import io.camunda.exporter.cache.ExporterEntityCache;
import io.camunda.exporter.cache.form.CachedFormEntity;
import io.camunda.exporter.store.BatchRequest;
import io.camunda.exporter.utils.ExporterUtil;
import io.camunda.webapps.schema.descriptors.tasklist.template.TaskTemplate;
import io.camunda.webapps.schema.entities.tasklist.TaskEntity;
import io.camunda.webapps.schema.entities.tasklist.TaskEntity.TaskImplementation;
import io.camunda.webapps.schema.entities.tasklist.TaskJoinRelationship;
import io.camunda.webapps.schema.entities.tasklist.TaskJoinRelationship.TaskJoinRelationshipType;
import io.camunda.webapps.schema.entities.tasklist.TaskState;
import io.camunda.zeebe.protocol.record.Record;
import io.camunda.zeebe.protocol.record.ValueType;
import io.camunda.zeebe.protocol.record.intent.UserTaskIntent;
import io.camunda.zeebe.protocol.record.value.UserTaskRecordValue;
import java.time.Instant;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserTaskHandler implements ExportHandler {

  private static final Logger LOGGER = LoggerFactory.getLogger(UserTaskHandler.class);
  private static final Set SUPPORTED_INTENTS =
      EnumSet.of(
          UserTaskIntent.CREATED,
          UserTaskIntent.COMPLETED,
          UserTaskIntent.CANCELED,
          UserTaskIntent.MIGRATED,
          UserTaskIntent.ASSIGNED,
          UserTaskIntent.UPDATED);
  private final String indexName;
  private final ExporterEntityCache formCache;

  public UserTaskHandler(
      final String indexName, final ExporterEntityCache formCache) {
    this.indexName = indexName;
    this.formCache = formCache;
  }

  @Override
  public ValueType getHandledValueType() {
    return ValueType.USER_TASK;
  }

  @Override
  public Class getEntityType() {
    return TaskEntity.class;
  }

  @Override
  public boolean handlesRecord(final Record record) {
    return SUPPORTED_INTENTS.contains(record.getIntent());
  }

  @Override
  public List generateIds(final Record record) {
    return List.of(String.valueOf(record.getValue().getElementInstanceKey()));
  }

  @Override
  public TaskEntity createNewEntity(final String id) {
    return new TaskEntity().setId(id).setChangedAttributes(new ArrayList<>());
  }

  @Override
  public void updateEntity(final Record record, final TaskEntity entity) {
    entity.setProcessInstanceId(String.valueOf(record.getValue().getProcessInstanceKey()));
    entity.setAction(record.getValue().getAction());
    switch (record.getIntent()) {
      case UserTaskIntent.CREATED -> createTaskEntity(entity, record);
      case UserTaskIntent.ASSIGNED -> {
        entity.getChangedAttributes().add("assignee");
        if (ExporterUtil.isEmpty(record.getValue().getAssignee())) {
          entity.setAssignee(null);
        } else {
          entity.setAssignee(record.getValue().getAssignee());
        }
      }
      case UserTaskIntent.UPDATED -> {
        for (final String attribute : record.getValue().getChangedAttributes()) {
          entity.getChangedAttributes().add(attribute);
          switch (attribute) {
            case "candidateGroupsList" ->
                entity.setCandidateGroups(
                    record.getValue().getCandidateGroupsList().toArray(new String[0]));
            case "candidateUsersList" ->
                entity.setCandidateUsers(
                    record.getValue().getCandidateUsersList().toArray(new String[0]));
            case "dueDate" ->
                entity.setDueDate(ExporterUtil.toOffsetDateTime(record.getValue().getDueDate()));
            case "followUpDate" ->
                entity.setFollowUpDate(
                    ExporterUtil.toOffsetDateTime(record.getValue().getFollowUpDate()));
            case "priority" -> entity.setPriority(record.getValue().getPriority());
            default ->
                LOGGER.warn(
                    "Attribute update not mapped while importing ZEEBE_USER_TASKS: {}", attribute);
          }
        }
      }
      case UserTaskIntent.COMPLETED, UserTaskIntent.CANCELED ->
          entity
              .setState(
                  record.getIntent().equals(UserTaskIntent.COMPLETED)
                      ? TaskState.COMPLETED
                      : TaskState.CANCELED)
              .setCompletionTime(
                  ExporterUtil.toZonedOffsetDateTime(Instant.ofEpochMilli(record.getTimestamp())));
      case UserTaskIntent.MIGRATED ->
          entity
              .setFlowNodeBpmnId(record.getValue().getElementId())
              .setBpmnProcessId(record.getValue().getBpmnProcessId())
              .setProcessDefinitionId(String.valueOf(record.getValue().getProcessDefinitionKey()))
              .setState(TaskState.CREATED);
      default -> {}
    }

    final TaskJoinRelationship joinRelation = new TaskJoinRelationship();
    joinRelation.setName(TaskJoinRelationshipType.TASK.getType());
    joinRelation.setParent(Long.valueOf(entity.getProcessInstanceId()));
    entity.setJoin(joinRelation);
  }

  @Override
  public void flush(final TaskEntity entity, final BatchRequest batchRequest) {

    final Map updateFields = getUpdatedFields(entity);

    batchRequest.upsertWithRouting(
        indexName, entity.getId(), entity, updateFields, entity.getProcessInstanceId());
  }

  @Override
  public String getIndexName() {
    return indexName;
  }

  private Map getUpdatedFields(final TaskEntity entity) {

    final Map updateFields = new HashMap<>();
    if (entity.getChangedAttributes() != null) {
      for (final String changedAttribute : entity.getChangedAttributes()) {
        switch (changedAttribute) {
          case "assignee" -> updateFields.put(TaskTemplate.ASSIGNEE, entity.getAssignee());
          case "candidateGroupsList" ->
              updateFields.put(TaskTemplate.CANDIDATE_GROUPS, entity.getCandidateGroups());
          case "candidateUsersList" ->
              updateFields.put(TaskTemplate.CANDIDATE_USERS, entity.getCandidateUsers());
          case "dueDate" -> updateFields.put(TaskTemplate.DUE_DATE, entity.getDueDate());
          case "followUpDate" ->
              updateFields.put(TaskTemplate.FOLLOW_UP_DATE, entity.getFollowUpDate());
          case "priority" -> updateFields.put(TaskTemplate.PRIORITY, entity.getPriority());
          default ->
              LOGGER.warn(
                  "Attribute update not mapped while importing ZEEBE_USER_TASKS: {}",
                  changedAttribute);
        }
      }
    }
    if (entity.getCompletionTime() != null) {
      updateFields.put(TaskTemplate.COMPLETION_TIME, entity.getCompletionTime());
    }

    if (entity.getChangedAttributes() != null && !entity.getChangedAttributes().isEmpty()) {
      updateFields.put(TaskTemplate.CHANGED_ATTRIBUTES, entity.getChangedAttributes());
    }
    if (entity.getAction() != null) {
      updateFields.put(TaskTemplate.ACTION, entity.getAction());
    }
    if (entity.getState() != null) {
      updateFields.put(TaskTemplate.STATE, entity.getState());
    }
    if (entity.getFlowNodeBpmnId() != null) {
      updateFields.put(TaskTemplate.FLOW_NODE_BPMN_ID, entity.getFlowNodeBpmnId());
    }
    if (entity.getProcessDefinitionId() != null) {
      updateFields.put(TaskTemplate.PROCESS_DEFINITION_ID, entity.getProcessDefinitionId());
    }
    if (entity.getBpmnProcessId() != null) {
      updateFields.put(TaskTemplate.BPMN_PROCESS_ID, entity.getBpmnProcessId());
    }

    return updateFields;
  }

  private void createTaskEntity(final TaskEntity entity, final Record record) {
    final var formKey =
        record.getValue().getFormKey() > 0 ? String.valueOf(record.getValue().getFormKey()) : null;

    entity
        .setImplementation(TaskImplementation.ZEEBE_USER_TASK)
        .setId(String.valueOf(record.getValue().getElementInstanceKey()))
        .setKey(record.getKey())
        .setState(TaskState.CREATED)
        .setAssignee(
            ExporterUtil.isEmpty(record.getValue().getAssignee())
                ? null
                : record.getValue().getAssignee())
        .setDueDate(ExporterUtil.toOffsetDateTime(record.getValue().getDueDate()))
        .setFollowUpDate(ExporterUtil.toOffsetDateTime(record.getValue().getFollowUpDate()))
        .setFlowNodeInstanceId(String.valueOf(record.getValue().getElementInstanceKey()))
        .setProcessInstanceId(String.valueOf(record.getValue().getProcessInstanceKey()))
        .setFlowNodeBpmnId(record.getValue().getElementId())
        .setBpmnProcessId(record.getValue().getBpmnProcessId())
        .setProcessDefinitionId(String.valueOf(record.getValue().getProcessDefinitionKey()))
        .setProcessDefinitionVersion(record.getValue().getProcessDefinitionVersion())
        .setFormKey(!ExporterUtil.isEmpty(formKey) ? formKey : null)
        .setExternalFormReference(
            ExporterUtil.isEmpty(record.getValue().getExternalFormReference())
                ? null
                : record.getValue().getExternalFormReference())
        .setCustomHeaders(record.getValue().getCustomHeaders())
        .setPriority(record.getValue().getPriority())
        .setPartitionId(record.getPartitionId())
        .setTenantId(record.getValue().getTenantId())
        .setPosition(record.getPosition())
        .setAction(
            ExporterUtil.isEmpty(record.getValue().getAction())
                ? null
                : record.getValue().getAction())
        .setCreationTime(
            ExporterUtil.toZonedOffsetDateTime(Instant.ofEpochMilli(record.getTimestamp())));

    if (!record.getValue().getCandidateGroupsList().isEmpty()) {
      entity.setCandidateGroups(record.getValue().getCandidateGroupsList().toArray(new String[0]));
    }

    if (!record.getValue().getCandidateUsersList().isEmpty()) {
      entity.setCandidateUsers(record.getValue().getCandidateUsersList().toArray(new String[0]));
    }

    if (!ExporterUtil.isEmpty(formKey)) {
      formCache
          .get(formKey)
          .ifPresent(c -> entity.setFormId(c.formId()).setFormVersion(c.formVersion()));
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy