Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new example: process state query #295

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions process-state-query/README.md
Original file line number Diff line number Diff line change
@@ -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).
41 changes: 41 additions & 0 deletions process-state-query/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.example</groupId>
<artifactId>process-state-query</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<version.java>17</version.java>
<maven.compiler.source>${version.java}</maven.compiler.source>
<maven.compiler.target>${version.java}</maven.compiler.target>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.1.5</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.camunda.spring</groupId>
<artifactId>spring-boot-starter-camunda</artifactId>
<version>8.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<FlownodeInstance> flownodeInstances = camundaOperateClient.searchFlownodeInstances(new SearchQuery.Builder()
.filter(new FlownodeInstanceFilter.Builder()
.processInstanceKey(processInstance.getKey())
.build())
.build());
List<Incident> incidents = camundaOperateClient.searchIncidents(new SearchQuery.Builder()
.filter(new IncidentFilter.Builder()
.processInstanceKey(processInstance.getKey())
.build())
.build());
List<Variable> 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<IncidentDto> buildIncidents(List<Incident> 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<ElementInstanceDto> buildElementInstances(
List<FlownodeInstance> flownodeInstances, List<Variable> variables
) {
return flownodeInstances
.stream()
.map(fni -> buildElementInstance(fni, variables))
.toList();
}

private ElementInstanceDto buildElementInstance(FlownodeInstance flownodeInstance, List<Variable> 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<VariableDto> buildVariables(List<Variable> 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());
}
}
Original file line number Diff line number Diff line change
@@ -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<ElementInstanceDto> elementInstances,
List<IncidentDto> incidents, List<VariableDto> variables, String state,
LocalDateTime startDate, LocalDateTime endDate) {
public record ElementInstanceDto(long elementInstanceKey, String elementId, String elementName,
List<VariableDto> 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) {

}
}
10 changes: 10 additions & 0 deletions process-state-query/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
operate:
client:
enabled: true

camunda:
operate:
client:
url: http://localhost:8081
username: demo
password: demo
Loading