From 6ccfda71bf94d5936911ac98b1278e031ff57103 Mon Sep 17 00:00:00 2001 From: Jonathan Lukas Date: Fri, 8 Dec 2023 07:31:36 +0100 Subject: [PATCH] new example: process state query --- process-state-query/README.md | 7 + process-state-query/pom.xml | 41 +++++ .../io/camunda/processStateQuery/App.java | 11 ++ .../ProcessStateController.java | 143 ++++++++++++++++++ .../processStateQuery/ProcessStateDto.java | 21 +++ .../src/main/resources/application.yaml | 10 ++ 6 files changed, 233 insertions(+) create mode 100644 process-state-query/README.md create mode 100644 process-state-query/pom.xml create mode 100644 process-state-query/src/main/java/io/camunda/processStateQuery/App.java create mode 100644 process-state-query/src/main/java/io/camunda/processStateQuery/ProcessStateController.java create mode 100644 process-state-query/src/main/java/io/camunda/processStateQuery/ProcessStateDto.java create mode 100644 process-state-query/src/main/resources/application.yaml diff --git a/process-state-query/README.md b/process-state-query/README.md new file mode 100644 index 00000000..4eb08ab2 --- /dev/null +++ b/process-state-query/README.md @@ -0,0 +1,7 @@ +# Query Process instance state + +This code example shows how to query a process instance state. + +Therefore, it uses the Operate REST API. + +The `application.yaml` is configured to run with a local docker-compose core dev setup (without identity). \ No newline at end of file diff --git a/process-state-query/pom.xml b/process-state-query/pom.xml new file mode 100644 index 00000000..0c7829da --- /dev/null +++ b/process-state-query/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.example + process-state-query + 1.0-SNAPSHOT + + + UTF-8 + 17 + ${version.java} + ${version.java} + + + + + + org.springframework.boot + spring-boot-dependencies + 3.1.5 + import + pom + + + + + + + io.camunda.spring + spring-boot-starter-camunda + 8.3.1 + + + org.springframework.boot + spring-boot-starter-web + + + \ No newline at end of file diff --git a/process-state-query/src/main/java/io/camunda/processStateQuery/App.java b/process-state-query/src/main/java/io/camunda/processStateQuery/App.java new file mode 100644 index 00000000..2fb49ffc --- /dev/null +++ b/process-state-query/src/main/java/io/camunda/processStateQuery/App.java @@ -0,0 +1,11 @@ +package io.camunda.processStateQuery; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class App { + public static void main(String[] args) { + SpringApplication.run(App.class,args); + } +} diff --git a/process-state-query/src/main/java/io/camunda/processStateQuery/ProcessStateController.java b/process-state-query/src/main/java/io/camunda/processStateQuery/ProcessStateController.java new file mode 100644 index 00000000..83587fff --- /dev/null +++ b/process-state-query/src/main/java/io/camunda/processStateQuery/ProcessStateController.java @@ -0,0 +1,143 @@ +package io.camunda.processStateQuery; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.operate.CamundaOperateClient; +import io.camunda.operate.dto.FlownodeInstance; +import io.camunda.operate.dto.Incident; +import io.camunda.operate.dto.ProcessDefinition; +import io.camunda.operate.dto.ProcessInstance; +import io.camunda.operate.dto.Variable; +import io.camunda.operate.exception.OperateException; +import io.camunda.operate.search.FlownodeInstanceFilter; +import io.camunda.operate.search.IncidentFilter; +import io.camunda.operate.search.SearchQuery; +import io.camunda.operate.search.VariableFilter; +import io.camunda.processStateQuery.ProcessStateDto.ElementInstanceDto; +import io.camunda.processStateQuery.ProcessStateDto.IncidentDto; +import io.camunda.processStateQuery.ProcessStateDto.VariableDto; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.List; + +@RestController +public class ProcessStateController { + private static final Logger LOG = LoggerFactory.getLogger(ProcessStateController.class); + private final CamundaOperateClient camundaOperateClient; + private final ObjectMapper objectMapper; + + @Autowired + public ProcessStateController(CamundaOperateClient camundaOperateClient, ObjectMapper objectMapper) { + this.camundaOperateClient = camundaOperateClient; + this.objectMapper = objectMapper; + } + + @GetMapping("/process-states/{key}") + public ProcessStateDto getProcessState(@PathVariable("key") long key) throws OperateException { + LOG.info("Fetching process instance with key {}", key); + ProcessInstance processInstance = camundaOperateClient.getProcessInstance(key); + ProcessDefinition processDefinition = camundaOperateClient.getProcessDefinition(processInstance.getProcessDefinitionKey()); + List flownodeInstances = camundaOperateClient.searchFlownodeInstances(new SearchQuery.Builder() + .filter(new FlownodeInstanceFilter.Builder() + .processInstanceKey(processInstance.getKey()) + .build()) + .build()); + List incidents = camundaOperateClient.searchIncidents(new SearchQuery.Builder() + .filter(new IncidentFilter.Builder() + .processInstanceKey(processInstance.getKey()) + .build()) + .build()); + List variables = camundaOperateClient + .searchVariables(new SearchQuery.Builder() + .filter(new VariableFilter.Builder() + .processInstanceKey(processInstance.getKey()) + .build()) + .build()) + .stream() + .map(this::getVariable) + .toList(); + return new ProcessStateDto( + processInstance.getKey(), + processInstance.getProcessDefinitionKey(), + processInstance.getBpmnProcessId(), + processDefinition.getName(), + buildElementInstances(flownodeInstances, variables), + buildIncidents(incidents), + buildVariables(variables, processInstance.getKey()), + processInstance + .getState() + .toString(), + fromDate(processInstance.getStartDate()), + fromDate(processInstance.getEndDate()) + ); + } + + private List buildIncidents(List incidents) { + return incidents + .stream() + .map(i -> new IncidentDto(i.getKey(), i.getMessage(), i.getState(), fromDate(i.getCreationTime()))) + .toList(); + } + + private Variable getVariable(Variable variable) { + try { + return variable.getTruncated() ? camundaOperateClient.getVariable(variable.getKey()) : variable; + } catch (OperateException e) { + throw new RuntimeException(e); + } + } + + private List buildElementInstances( + List flownodeInstances, List variables + ) { + return flownodeInstances + .stream() + .map(fni -> buildElementInstance(fni, variables)) + .toList(); + } + + private ElementInstanceDto buildElementInstance(FlownodeInstance flownodeInstance, List variables) { + return new ElementInstanceDto( + flownodeInstance.getKey(), + flownodeInstance.getFlowNodeId(), + flownodeInstance.getFlowNodeName(), + buildVariables(variables, flownodeInstance.getKey()), + flownodeInstance + .getState() + .toString(), + fromDate(flownodeInstance.getStartDate()), + fromDate(flownodeInstance.getEndDate()) + ); + } + + private List buildVariables(List variables, Long scopeKey) { + return variables + .stream() + .filter(v -> v + .getScopeKey() + .equals(scopeKey)) + .map(v -> new VariableDto(v.getKey(), v.getName(), getVariableValue(v))) + .toList(); + } + + private JsonNode getVariableValue(Variable variable) { + try { + return objectMapper.readTree(variable.getValue()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + private LocalDateTime fromDate(Date date) { + return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); + } +} diff --git a/process-state-query/src/main/java/io/camunda/processStateQuery/ProcessStateDto.java b/process-state-query/src/main/java/io/camunda/processStateQuery/ProcessStateDto.java new file mode 100644 index 00000000..3a2d270e --- /dev/null +++ b/process-state-query/src/main/java/io/camunda/processStateQuery/ProcessStateDto.java @@ -0,0 +1,21 @@ +package io.camunda.processStateQuery; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.time.LocalDateTime; +import java.util.List; + +public record ProcessStateDto(long processInstanceKey, long processDefinitionKey, String bpmnProcessId, + String processName, List elementInstances, + List incidents, List variables, String state, + LocalDateTime startDate, LocalDateTime endDate) { + public record ElementInstanceDto(long elementInstanceKey, String elementId, String elementName, + List variables, String state, LocalDateTime startDate, + LocalDateTime endDate) {} + + public record IncidentDto(long incidentKey, String message, String state, LocalDateTime creationTime) {} + + public record VariableDto(long variableKey, String name, JsonNode value) { + + } +} diff --git a/process-state-query/src/main/resources/application.yaml b/process-state-query/src/main/resources/application.yaml new file mode 100644 index 00000000..a69f17ed --- /dev/null +++ b/process-state-query/src/main/resources/application.yaml @@ -0,0 +1,10 @@ +operate: + client: + enabled: true + +camunda: + operate: + client: + url: http://localhost:8081 + username: demo + password: demo \ No newline at end of file