Skip to content
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
3 changes: 3 additions & 0 deletions camunda-8-process-application/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
target
node
node_modules
24 changes: 24 additions & 0 deletions camunda-8-process-application/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Camunda 8 Process Application
built with 8.0.0

## Topic
Creation of a process application by using the APIs offered: Tasklist, Zeebe, Operate.

## Development and building

### Backend
Spring-Boot Application that is built using `mvn clean package` or run with an IDE

To run the Application, please make sure you have a `application-dev.yaml` in your `src/main/resources`that contains
the cluster credentials.

### Frontend
Vue3 Application that is built using `npm run build` or run in dev mode with `npm run dev`

## Packaging all toghether

By running `mvn clean package` on the parent, you will get a jar file inside the backend project that contains backend and frontend.
By providing credentials for the Zeebe Client while giving the API Client the required scopes (Tasklist, Operate, Zeebe), all clients will work with Cloud.

## Additional information

Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?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">
<parent>
<artifactId>camunda-8-process-application</artifactId>
<groupId>com.camunda.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>camunda-8-process-application-backend</artifactId>

<dependencies>
<dependency>
<groupId>io.camunda</groupId>
<artifactId>spring-zeebe-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.okta.spring</groupId>
<artifactId>okta-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>camunda-8-process-application-frontend</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.camunda.example;

import io.camunda.zeebe.spring.client.EnableZeebeClient;
import io.camunda.zeebe.spring.client.annotation.ZeebeDeployment;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;

@SpringBootApplication
@EnableZeebeClient
@ZeebeDeployment(resources = { "classpath*:**.bpmn", "classpath*:**.dmn" })
public class CloudTasklistApplication {
public static void main(String[] args) {
SpringApplication.run(CloudTasklistApplication.class, args);
}

@EnableWebSecurity
public static class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated();
http.oauth2Login();
http.oauth2Client();
http.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.camunda.example.client;

import com.fasterxml.jackson.databind.*;
import io.camunda.zeebe.client.*;
import io.grpc.*;
import lombok.*;
import org.slf4j.*;
import org.springframework.http.*;

import java.util.*;

public abstract class AbstractCredentialsRequiringClient {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final CredentialsProvider credentialsProvider;
private final ObjectMapper objectMapper;

protected AbstractCredentialsRequiringClient(CredentialsProvider credentialsProvider, ObjectMapper objectMapper) {
this.credentialsProvider = credentialsProvider;
this.objectMapper = objectMapper;
}

@SneakyThrows
protected HttpHeaders createHeaders(List<MediaType> accept) {
Metadata metadata = new Metadata();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(accept);
credentialsProvider.applyCredentials(metadata);
metadata
.keys()
.forEach(key -> {
metadata
.getAll(Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER))
.forEach(value -> {
headers.add(key, value);
});
});
return headers;
}

protected void logAsJson(String message, Object object) {
try {
log.debug(
message,
objectMapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(object)
);
} catch (Exception e) {
log.debug(message, object);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.camunda.example.client.operate;

import com.camunda.example.client.*;
import com.camunda.example.client.operate.model.*;
import com.fasterxml.jackson.databind.*;
import io.camunda.zeebe.client.*;
import io.github.resilience4j.retry.annotation.*;
import lombok.extern.slf4j.*;
import org.springframework.core.*;
import org.springframework.http.*;
import org.springframework.web.client.*;
import org.springframework.web.util.*;

import java.net.*;
import java.util.*;

@Slf4j
public abstract class AbstractOperateObjectEndpoint<T> extends AbstractCredentialsRequiringClient
implements OperateObjectEndpoint<T> {
public AbstractOperateObjectEndpoint(
RestTemplate restTemplate, URI operateEndpoint, CredentialsProvider credentialsProvider, ObjectMapper objectMapper
) {
super(credentialsProvider, objectMapper);
this.restTemplate = restTemplate;
this.operateEndpoint = operateEndpoint;
}

private final RestTemplate restTemplate;

private final URI operateEndpoint;

@Override
@Retry(name = "operate")
public ResultsDto<T> search(QueryDto<T> query) {
return call(List.of("search"),
HttpMethod.POST,
createEntity(Optional.of(query), List.of(MediaType.APPLICATION_JSON)),
resultsDtoTypeReference()
).getBody();
}

@Override
@Retry(name = "operate")
public T get(Long key) {
return call(List.of(String.valueOf(key)),
HttpMethod.GET,
createEntity(Optional.empty(),List.of(MediaType.APPLICATION_JSON)),
simpleTypeReference()
).getBody();
}

protected <Req, Res> ResponseEntity<Res> call(
List<String> pathSegments,
HttpMethod httpMethod,
HttpEntity<Req> httpEntity,
ParameterizedTypeReference<Res> typeReference
) {
return restTemplate.exchange(createEndpoint(pathSegments.toArray(new String[0])),
httpMethod,
httpEntity,
typeReference
);
}

protected abstract String endpointObjectType();

protected abstract ParameterizedTypeReference<T> simpleTypeReference();

protected abstract ParameterizedTypeReference<ResultsDto<T>> resultsDtoTypeReference();

protected URI createEndpoint(String... pathSegments) {
return UriComponentsBuilder
.fromUri(operateEndpoint)
.pathSegment(endpointObjectType())
.pathSegment(pathSegments)
.build()
.toUri();
}

protected <B> HttpEntity<B> createEntity(Optional<B> body, List<MediaType> accept) {
return body
.map(t -> new HttpEntity<>(t, createHeaders(accept)))
.orElseGet(() -> new HttpEntity<>(createHeaders(accept)));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.camunda.example.client.operate;

import lombok.*;
import lombok.extern.slf4j.*;
import org.springframework.stereotype.*;

@Slf4j
@Component
@Getter
public class OperateClient {
private final OperateProcessDefinitionsEndpoint processDefinitionsEndpoint;
private final OperateProcessInstancesEndpoint processInstancesEndpoint;
private final OperateIncidentsEndpoint incidentsEndpoint;
private final OperateFlowNodeInstancesEndpoint flowNodeInstancesEndpoint;
private final OperateVariablesEndpoint variablesEndpoint;

public OperateClient(
OperateProcessDefinitionsEndpoint processDefinitionsEndpoint,
OperateProcessInstancesEndpoint processInstancesEndpoint,
OperateIncidentsEndpoint incidentsEndpoint,
OperateFlowNodeInstancesEndpoint flowNodeInstancesEndpoint,
OperateVariablesEndpoint variablesEndpoint
) {
this.processDefinitionsEndpoint = processDefinitionsEndpoint;
this.processInstancesEndpoint = processInstancesEndpoint;
this.incidentsEndpoint = incidentsEndpoint;
this.flowNodeInstancesEndpoint = flowNodeInstancesEndpoint;
this.variablesEndpoint = variablesEndpoint;
}


}
Loading