Skip to content

Commit

Permalink
Showing 12 changed files with 182 additions and 581 deletions.
72 changes: 39 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -8,16 +8,49 @@ This project was intially designed to simplify communication between a java back

:information_source: 8.3+ Relesases of this client are generated against Rest endpoints.

:information_source: **8.3.3.3 changes the way to build authentication and client. Please check the following documentation**

# How to use the client
## Use the correct authentication

Depending on your setup, you may want to use different authentication mechanisms.
In case you're using a Camunda Platform without identity enabled, you should use the **SimpleAuthentication**

```java
SimpleConfig simpleConf = new SimpleConfig();
simpleConf.addProduct(Product.TASKLIST, new SimpleCredential("user", "pwd"));
Authentication auth = SimpleAuthentication.builder().simpleConfig(simpleConf).build();
```

In case you're using a Self Managed Camunda Platform with identity enabled (and Keycloak), you should use the **SelfManagedAuthentication**

```java
JwtConfig jwtConfig = new JwtConfig();
jwtConfig.addProduct(Product.TASKLIST, new JwtCredential("clientId", "clientSecret"));
Authentication auth = SelfManagedAuthentication.builder().jwtConfig(jwtConfig).build();
```

And finally, if you're using a SaaS environment, just use the **SaaSAuthentication**

```java
JwtConfig jwtConfig = new JwtConfig();
jwtConfig.addProduct(Product.TASKLIST, new JwtCredential("clientId", "clientSecret"));
Authentication auth = SaaSAuthentication.builder().jwtConfig(jwtConfig).build();
```

## Build your client

Simply build a CamundaTaskListClient that takes an authentication and the tasklist url as parameters.


```java
SimpleAuthentication sa = new SimpleAuthentication("demo", "demo");
CamundaTaskListClient client = CamundaTaskListClient.builder().taskListUrl("http://localhost:8081").shouldReturnVariables().shouldLoadTruncatedVariables().authentication(auth).build();
```
:information_source: **shouldReturnVariables()** will read variables along with tasks. This is not the recommended approach but rather a commodity. In real project implementation, we would recommend to load task variables only when required.

:information_source: **shouldLoadTruncatedVariables()** will execute a second call to read the variable if its value was truncated in the initial search.

//shouldReturnVariables will change the default behaviour for the client to query variables along with tasks.
CamundaTaskListClient client = new CamundaTaskListClient.Builder().taskListUrl("http://localhost:8081").shouldReturnVariables().authentication(sa).build();
## Make some queries
```java
//get tasks from a process instance (TaskSearch can take many more parameters)
TaskSearch ts = new TaskSearch().setProcessInstanceId("2251799818839086");
TaskList tasksFromInstance = client.getTasks(ts);
@@ -65,45 +98,18 @@ Form form = client.getForm(formId, processDefinitionId);
String schema = form.getSchema();
```



# Authentication
You can use the ***SimpleAuthentication*** to connect to a local Camunda TaskList if your setup is "simple": ***without identity and keycloak***.

To connect to the **SaaS** TaskList, you need to use the **SaasAuthentication**. The SaaSAuthentication requires the clientId and clientSecret

```java
SaasAuthentication sa = new SaasAuthentication("2~nB1MwkUU45FuXXX", "aBRKtreXQF3uD2MYYY");
CamundaTaskListClient client = new CamundaTaskListClient.Builder().authentication(sa)
.taskListUrl("https://bru-2.tasklist.camunda.io/757dbc30-5127-4bed-XXXX-XXXXXXXXXXXX").build();


client.getTasks(false, TaskState.CREATED, 50);
```

To connect to the **Local** TaskList with **Identity & Keycloak**, you need to use the **SelfManagedAuthentication**. The SelfManagedAuthentication requires the clientId and clientSecret. You can also change the Keycloak realm and the keycloakUrl depending on your installation.

```java
SelfManagedAuthentication sma = new SelfManagedAuthentication().clientId("java").clientSecret("foTPogjlI0hidwbDZcYFWzmU8FOQwLx0").baseUrl("http://localhost:18080").keycloakRealm("camunda-platform");
CamundaTaskListClient client = new CamundaTaskListClient.Builder().shouldReturnVariables().taskListUrl("http://localhost:8082/").authentication(sma).build();

client.getTasks(false, TaskState.CREATED, 50);
```

# use it in your project
You can import it to your maven or gradle project as a dependency

```xml
<dependency>
<groupId>io.camunda</groupId>
<artifactId>camunda-tasklist-client-java</artifactId>
<version>8.3.3.2</version>
<version>8.3.3.3</version>
</dependency>
```
# Troubleshooting



# Note
A similar library is available for operate there:
[camunda-operate-client-java](https://github.com/camunda-community-hub/camunda-operate-client-java)
[java-client-operate](https://github.com/camunda-community-hub/spring-zeebe/tree/main/camunda-sdk-java/java-client-operate)
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ plugins {
}

group = 'io.camunda'
version = '8.3.3.2'
version = '8.3.3.3'

sourceCompatibility = '11'

@@ -29,7 +29,7 @@ dependencies {
api "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version"
api "org.openapitools:jackson-databind-nullable:0.2.1"
api "jakarta.annotation:jakarta.annotation-api:$jakarta_annotation_version"

api "io.camunda.spring:java-common:8.3.2-rc4"

testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
148 changes: 47 additions & 101 deletions src/main/java/io/camunda/tasklist/CamundaTaskListClient.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package io.camunda.tasklist;

import static io.camunda.tasklist.util.ConverterUtils.*;
import static io.camunda.tasklist.util.ConverterUtils.improveVariable;
import static io.camunda.tasklist.util.ConverterUtils.toVariable;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.camunda.tasklist.auth.AuthInterface;

import io.camunda.common.auth.Product;
import io.camunda.tasklist.dto.DateFilter;
import io.camunda.tasklist.dto.Form;
import io.camunda.tasklist.dto.Pagination;
@@ -27,23 +37,11 @@
import io.camunda.tasklist.generated.model.VariableInputDTO;
import io.camunda.tasklist.generated.model.VariablesSearchRequest;
import io.camunda.tasklist.util.ConverterUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import io.camunda.tasklist.util.JwtUtils;

public class CamundaTaskListClient {
private static final String CAMUNDA_FORMS_PREFIX = "camunda-forms:bpmn:";

private AuthInterface authentication;

private String taskListUrl;

private boolean defaultShouldReturnVariables;
private boolean defaultShouldLoadTruncatedVariables;

private CamundaTaskListClientProperties properties;

private int tokenExpiration;

@@ -52,6 +50,17 @@ public class CamundaTaskListClient {
private TaskApi taskApi;
private FormApi formApi;
private VariablesApi variablesApi;

protected CamundaTaskListClient(CamundaTaskListClientProperties properties) throws TaskListException {
this.properties = properties;
this.apiClient.updateBaseUri(properties.taskListUrl);

this.taskApi = new TaskApi(this.apiClient);
this.formApi = new FormApi(this.apiClient);
this.variablesApi = new VariablesApi(this.apiClient);

authenticate();
}

public Task unclaim(String taskId) throws TaskListException {
try {
@@ -97,12 +106,12 @@ public Task completeTask(String taskId, Map<String, Object> variablesMap)
public TaskList getTasks(Boolean assigned, TaskState state, Integer pageSize)
throws TaskListException {
return getTasks(
assigned, state, defaultShouldReturnVariables, new Pagination().setPageSize(pageSize));
assigned, state, properties.defaultShouldReturnVariables, new Pagination().setPageSize(pageSize));
}

public TaskList getTasks(Boolean assigned, TaskState state, Pagination pagination)
throws TaskListException {
return getTasks(assigned, state, defaultShouldReturnVariables, pagination);
return getTasks(assigned, state, properties.defaultShouldReturnVariables, pagination);
}

public TaskList getTasks(
@@ -121,12 +130,12 @@ public TaskList getTasks(
public TaskList getAssigneeTasks(String assigneeId, TaskState state, Integer pageSize)
throws TaskListException {
return getAssigneeTasks(
assigneeId, state, defaultShouldReturnVariables, new Pagination().setPageSize(pageSize));
assigneeId, state, properties.defaultShouldReturnVariables, new Pagination().setPageSize(pageSize));
}

public TaskList getAssigneeTasks(String assigneeId, TaskState state, Pagination pagination)
throws TaskListException {
return getAssigneeTasks(assigneeId, state, defaultShouldReturnVariables, pagination);
return getAssigneeTasks(assigneeId, state, properties.defaultShouldReturnVariables, pagination);
}

public TaskList getAssigneeTasks(
@@ -145,12 +154,12 @@ public TaskList getAssigneeTasks(
public TaskList getGroupTasks(String group, TaskState state, Integer pageSize)
throws TaskListException {
return getGroupTasks(
group, state, defaultShouldReturnVariables, new Pagination().setPageSize(pageSize));
group, state, properties.defaultShouldReturnVariables, new Pagination().setPageSize(pageSize));
}

public TaskList getGroupTasks(String group, TaskState state, Pagination pagination)
throws TaskListException {
return getGroupTasks(group, state, defaultShouldReturnVariables, pagination);
return getGroupTasks(group, state, properties.defaultShouldReturnVariables, pagination);
}

public TaskList getGroupTasks(
@@ -167,7 +176,7 @@ public TaskList getGroupTasks(
}

public Task getTask(String taskId) throws TaskListException {
return getTask(taskId, defaultShouldReturnVariables);
return getTask(taskId, properties.defaultShouldReturnVariables);
}

public Task getTask(String taskId, boolean withVariables) throws TaskListException {
@@ -224,8 +233,8 @@ public Variable getVariable(String variableId) throws TaskListException {

public Form getForm(String formId, String processDefinitionId) throws TaskListException {
try {
if (formId.startsWith(CAMUNDA_FORMS_PREFIX)) {
formId = formId.substring(CAMUNDA_FORMS_PREFIX.length());
if (formId.startsWith(CamundaTaskListClientProperties.CAMUNDA_FORMS_PREFIX)) {
formId = formId.substring(CamundaTaskListClientProperties.CAMUNDA_FORMS_PREFIX.length());
}
return ConverterUtils.toForm(formApi.getForm(formId, processDefinitionId));
} catch (ApiException e) {
@@ -298,7 +307,7 @@ private Pagination getSearchPagination(TaskList taskList, SearchType type) {

public TaskList getTasks(TaskSearch search) throws TaskListException {
if (search.getWithVariables() == null) {
search.setWithVariables(defaultShouldReturnVariables);
search.setWithVariables(properties.defaultShouldReturnVariables);
}
return getTasks(
search.getCandidateUser(),
@@ -450,93 +459,30 @@ public void loadVariables(List<Task> tasks) throws TaskListException {
}
}

public String getTaskListUrl() {
return taskListUrl;
}

public void setTokenExpiration(int tokenExpiration) {
this.tokenExpiration = tokenExpiration;
}

private void reconnectEventually() throws TaskListException {
if (this.tokenExpiration > 0
&& this.tokenExpiration < (System.currentTimeMillis() / 1000 - 3)) {
authentication.authenticate(this);
authenticate();
}
}

public void setAuthCookie(String cookie) {
this.apiClient.setRequestInterceptor(builder -> builder.header("cookie", cookie));
this.taskApi = new TaskApi(this.apiClient);
this.formApi = new FormApi(this.apiClient);
}

public void setBearerToken(String token) {
this.apiClient.setRequestInterceptor(
builder -> builder.header("Authorization", "Bearer " + token));
public void authenticate() throws TaskListException {
Map.Entry<String, String> header = properties.authentication.getTokenHeader(Product.TASKLIST);
if (header.getValue().startsWith("Bearer ")) {
this.tokenExpiration = JwtUtils.getExpiration(header.getValue().substring(7));
}
this.apiClient.setRequestInterceptor(builder -> builder.header(header.getKey(), header.getValue()));
this.taskApi = new TaskApi(this.apiClient);
this.formApi = new FormApi(this.apiClient);
}



public static class Builder {

private AuthInterface authentication;

private String taskListUrl;

private boolean defaultShouldReturnVariables = false;
private boolean defaultShouldLoadTruncatedVariables = false;

public Builder() {}

public Builder authentication(AuthInterface authentication) {
this.authentication = authentication;
return this;
}

public Builder taskListUrl(String taskListUrl) {
this.taskListUrl = taskListUrl;
return this;
}

/**
* Default behaviour will be to get variables along with tasks. Default value is false. Can also
* be overwritten in the getTasks methods
*
* @return the builder
*/
public Builder shouldReturnVariables() {
this.defaultShouldReturnVariables = true;
return this;
}

public Builder shouldLoadTruncatedVariables() {
this.defaultShouldLoadTruncatedVariables = true;
return this;
}

public CamundaTaskListClient build() throws TaskListException {
CamundaTaskListClient client = new CamundaTaskListClient();
client.authentication = authentication;
client.taskListUrl = taskListUrl;
client.defaultShouldReturnVariables = defaultShouldReturnVariables;
client.defaultShouldLoadTruncatedVariables = defaultShouldLoadTruncatedVariables;

client.apiClient.updateBaseUri(formatUrl(taskListUrl));

client.taskApi = new TaskApi(client.apiClient);
client.formApi = new FormApi(client.apiClient);
client.variablesApi = new VariablesApi(client.apiClient);

authentication.authenticate(client);
return client;
}

private String formatUrl(String url) {
if (url.endsWith("/")) {
return url.substring(0, url.length() - 1);
}
return url;
}
public static CamundaTaskListClientBuilder builder() {
return new CamundaTaskListClientBuilder();
}
}
Loading

0 comments on commit 778ee71

Please sign in to comment.