Skip to content

Commit

Permalink
Closes Taskana#612: Switch from standard http client to OkHttp Client
Browse files Browse the repository at this point in the history
the default JdkHttpClient does not support all HTTP Methods for example PATCH
switching to OkHttpClient supports all HTTP Methods and is more performant

2 new properties
* `okhttp.connection-timeout` - time in milliseconds to establish a connection
* `okhttp.read-timeout` - time to wait for response
  • Loading branch information
arolfes committed Nov 20, 2023
1 parent b414f2e commit 2ef249c
Show file tree
Hide file tree
Showing 11 changed files with 139 additions and 77 deletions.
6 changes: 6 additions & 0 deletions taskana-adapter-camunda-spring-boot-test/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@
<version>${version.jakarta.annotation}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import pro.taskana.TaskanaConfiguration;
import pro.taskana.adapter.systemconnector.camunda.api.impl.HttpHeaderProvider;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.api.exceptions.ClassificationNotFoundException;
import pro.taskana.classification.api.models.Classification;
Expand All @@ -35,15 +39,16 @@ public abstract class AbsIntegrationTest {

private static boolean isInitialised = false;

@LocalServerPort private Integer port;

@Value("${taskana.adapter.scheduler.run.interval.for.start.taskana.tasks.in.milliseconds}")
protected long adapterTaskPollingInterval;

@Value("${taskana.adapter.scheduler.run.interval.for.complete.referenced.tasks.in.milliseconds}")
protected long adapterCompletionPollingInterval;

@Value(
"${taskana.adapter.scheduler.run.interval.for.check.finished.referenced."
+ "tasks.in.milliseconds}")
"${taskana.adapter.scheduler.run.interval.for.check.finished.referenced.tasks.in.milliseconds}")
protected long adapterCancelledClaimPollingInterval;

@Value("${taskana.adapter.scheduler.run.interval.for.claim.referenced.tasks.in.milliseconds}")
Expand All @@ -69,9 +74,12 @@ public abstract class AbsIntegrationTest {
@Resource(name = "camundaBpmDataSource")
protected DataSource camundaBpmDataSource;

@Autowired private TestRestTemplate restTemplate;
private TestRestTemplate restTemplate;

@Autowired private ProcessEngineConfiguration processEngineConfiguration;

@Autowired private HttpHeaderProvider httpHeaderProvider;

@Resource(name = "taskanaDataSource")
private DataSource taskanaDataSource;

Expand Down Expand Up @@ -101,11 +109,19 @@ public void setUp() throws Exception {
isInitialised = true;
}

this.restTemplate =
new TestRestTemplate(
new RestTemplateBuilder()
.rootUri("http://localhost:" + port)
.requestFactory(OkHttp3ClientHttpRequestFactory.class));
// set up camunda requester and taskanaEngine-Taskservice
this.camundaProcessengineRequester =
new CamundaProcessengineRequester(
this.processEngineConfiguration.getProcessEngineName(), this.restTemplate);
this.taskanaOutboxRequester = new TaskanaOutboxRequester(this.restTemplate);
this.processEngineConfiguration.getProcessEngineName(),
this.restTemplate,
this.httpHeaderProvider);
this.taskanaOutboxRequester =
new TaskanaOutboxRequester(this.restTemplate, this.httpHeaderProvider);
this.taskService = taskanaEngine.getTaskService();

// adjust polling interval, give adapter a little more time
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@
import org.json.JSONObject;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import pro.taskana.adapter.systemconnector.camunda.api.impl.HttpHeaderProvider;

/** Class to assist with building requests against the Camunda REST API. */
public class CamundaProcessengineRequester {
Expand All @@ -28,25 +27,33 @@ public class CamundaProcessengineRequester {

private final String processEngineKey;

private final HttpHeaderProvider httpHeaderProvider;

/**
* Constructor for setting up a requester for a process engine with a key other than "default".
*
* @param processEngineKey the key of the camunda process engine to be called.
* @param restTemplate the {@link TestRestTemplate} to be used for the REST calls.
* @param httpHeaderProvider httpHeaderProvider to set correct headers on HTTP Request
*/
public CamundaProcessengineRequester(String processEngineKey, TestRestTemplate restTemplate) {
public CamundaProcessengineRequester(
String processEngineKey,
TestRestTemplate restTemplate,
HttpHeaderProvider httpHeaderProvider) {
this.processEngineKey = processEngineKey;
this.restTemplate = restTemplate;
this.httpHeaderProvider = httpHeaderProvider;
}

/**
* Default constructor to use the default process engine with its key "default".
*
* @param restTemplate the {@link TestRestTemplate} to be used for the REST calls.
* @param httpHeaderProvider httpHeaderProvider to set correct headers on HTTP Request
*/
public CamundaProcessengineRequester(TestRestTemplate restTemplate) {
this.processEngineKey = "default";
this.restTemplate = restTemplate;
public CamundaProcessengineRequester(
TestRestTemplate restTemplate, HttpHeaderProvider httpHeaderProvider) {
this("default", restTemplate, httpHeaderProvider);
}

/**
Expand All @@ -66,7 +73,8 @@ public String startCamundaProcessAndReturnId(String processKey, String variables
+ PROCESS_DEFINITION_KEY_PATH
+ processKey
+ PROCESS_DEFINITION_START_PATH;
HttpEntity<String> requestEntity = prepareEntityFromBody("{" + variables + "}");
HttpEntity<String> requestEntity =
httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi("{" + variables + "}");

ResponseEntity<String> answer =
restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
Expand All @@ -89,7 +97,7 @@ public List<String> getTaskIdsFromProcessInstanceId(String processInstanceId)
List<String> returnList = new ArrayList<String>();

String url = BASIC_ENGINE_PATH + this.processEngineKey + TASK_PATH;
HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<Void> requestEntity = httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi();

ResponseEntity<String> answer =
this.restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
Expand Down Expand Up @@ -120,7 +128,8 @@ public boolean completeTaskWithId(String camundaTaskId) throws JSONException {
+ "/"
+ camundaTaskId
+ COMPLETE_TASK_PATH;
HttpEntity<String> requestEntity = this.prepareEntityFromBody("{}");
HttpEntity<String> requestEntity =
httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi("{}");
ResponseEntity<String> answer =
this.restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
if (answer.getStatusCode().equals(HttpStatus.NO_CONTENT)) {
Expand All @@ -145,7 +154,7 @@ public boolean completeTaskWithId(String camundaTaskId) throws JSONException {
*/
public boolean getTaskFromTaskId(String camundaTaskId) throws JSONException {
String url = BASIC_ENGINE_PATH + this.processEngineKey + TASK_PATH + "/" + camundaTaskId;
HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<Void> requestEntity = httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi();
ResponseEntity<String> response =
restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
JSONObject taskRetrievalAnswerJson = new JSONObject(response.getBody());
Expand All @@ -170,7 +179,7 @@ public boolean getTaskFromHistoryFromTaskId(String camundaTaskId) throws JSONExc
+ TASK_PATH
+ "/?taskId="
+ camundaTaskId;
HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<Void> requestEntity = httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi();
ResponseEntity<String> response =
restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
// no task found will only show in empty body
Expand All @@ -196,7 +205,7 @@ public boolean isCorrectAssigneeFromHistory(String camundaTaskId, String assigne
+ TASK_PATH
+ "/?taskId="
+ camundaTaskId;
HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<Void> requestEntity = httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi();
ResponseEntity<String> response =
restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
// no task found will only show in empty body
Expand Down Expand Up @@ -228,7 +237,8 @@ public boolean deleteProcessInstanceWithId(String processInstanceId, boolean ski
if (skipCustomListeners) {
url += "?skipCustomListeners=true";
}
HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<String> requestEntity =
httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi("{}");
ResponseEntity<String> answer =
this.restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, String.class);
if (HttpStatus.NO_CONTENT.equals(answer.getStatusCode())) {
Expand All @@ -254,7 +264,7 @@ public boolean deleteProcessInstanceWithId(String processInstanceId, boolean ski
public boolean isCorrectAssignee(String camundaTaskId, String assigneeValueToVerify) {

String requestUrl = BASIC_ENGINE_PATH + this.processEngineKey + TASK_PATH + "/" + camundaTaskId;
HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<Void> requestEntity = httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi();
ResponseEntity<String> responseEntity =
restTemplate.exchange(requestUrl, HttpMethod.GET, requestEntity, String.class);
JSONObject taskRetrievalAnswerJson = new JSONObject(responseEntity.getBody());
Expand All @@ -273,16 +283,4 @@ public boolean isCorrectAssignee(String camundaTaskId, String assigneeValueToVer

return false;
}

/**
* Helper method to create an HttpEntity from a provided body in JSON-format.
*
* @param jsonBody the body of the HttpEntity
* @return the created HttpEntity
*/
private HttpEntity<String> prepareEntityFromBody(String jsonBody) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return new HttpEntity<String>(jsonBody, headers);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,14 @@
import org.json.JSONObject;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import pro.taskana.adapter.camunda.outbox.rest.model.CamundaTaskEvent;
import pro.taskana.adapter.impl.ReferencedTaskClaimCanceler;
import pro.taskana.adapter.impl.ReferencedTaskClaimer;
import pro.taskana.adapter.impl.ReferencedTaskCompleter;
import pro.taskana.adapter.impl.TaskanaTaskStarter;
import pro.taskana.adapter.impl.TaskanaTaskTerminator;
import pro.taskana.adapter.manager.AdapterManager;
import pro.taskana.adapter.test.TaskanaAdapterTestApplication;
import pro.taskana.common.test.security.JaasExtension;
Expand All @@ -35,14 +27,7 @@
webEnvironment = WebEnvironment.DEFINED_PORT)
@AutoConfigureWebTestClient
@ExtendWith(JaasExtension.class)
// Disable Schedulers so tasks stay in OutboxDB
@MockBean(ReferencedTaskCompleter.class)
@MockBean(ReferencedTaskClaimer.class)
@MockBean(ReferencedTaskClaimCanceler.class)
@MockBean(TaskanaTaskStarter.class)
@MockBean(TaskanaTaskTerminator.class)
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
@Disabled
@ContextConfiguration
public class CamundaTaskEventErrorHandlerTest extends AbsIntegrationTest {

@Autowired private AdapterManager adapterManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
import org.json.JSONException;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import pro.taskana.adapter.camunda.outbox.rest.model.CamundaTaskEvent;
import pro.taskana.adapter.camunda.outbox.rest.resource.CamundaTaskEventListResource;
import pro.taskana.adapter.systemconnector.camunda.api.impl.HttpHeaderProvider;

/** Class to assist with building requests against the TASKNA Outbox REST API. */
public class TaskanaOutboxRequester {
Expand All @@ -19,15 +18,20 @@ public class TaskanaOutboxRequester {

private final TestRestTemplate restTemplate;

public TaskanaOutboxRequester(TestRestTemplate restTemplate) {
private final HttpHeaderProvider httpHeaderProvider;

public TaskanaOutboxRequester(
TestRestTemplate restTemplate, HttpHeaderProvider httpHeaderProvider) {
this.restTemplate = restTemplate;
this.httpHeaderProvider = httpHeaderProvider;
}

public boolean deleteFailedEvent(int id) throws JSONException {

String url = BASIC_OUTBOX_PATH + "/" + id;

HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<String> requestEntity =
httpHeaderProvider.prepareEntityFromBodyForOutboxRestApi("{}");
ResponseEntity<String> answer =
this.restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, String.class);

Expand All @@ -41,7 +45,8 @@ public boolean deleteAllFailedEvents() throws JSONException {

String url = BASIC_OUTBOX_PATH + "/delete-failed-events";

HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<String> requestEntity =
httpHeaderProvider.prepareEntityFromBodyForOutboxRestApi("{}");
ResponseEntity<String> answer =
this.restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);

Expand All @@ -55,7 +60,7 @@ public List<CamundaTaskEvent> getFailedEvents() {

String url = BASIC_OUTBOX_PATH + "?retries=0";

HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<Void> requestEntity = httpHeaderProvider.prepareEntityFromBodyForOutboxRestApi();
ResponseEntity<CamundaTaskEventListResource> answer =
this.restTemplate.exchange(
url, HttpMethod.GET, requestEntity, CamundaTaskEventListResource.class);
Expand All @@ -67,7 +72,7 @@ public List<CamundaTaskEvent> getAllEvents() {

String url = BASIC_OUTBOX_PATH;

HttpEntity<String> requestEntity = prepareEntityFromBody("{}");
HttpEntity<Void> requestEntity = httpHeaderProvider.prepareEntityFromBodyForOutboxRestApi();
ResponseEntity<CamundaTaskEventListResource> answer =
this.restTemplate.exchange(
url, HttpMethod.GET, requestEntity, CamundaTaskEventListResource.class);
Expand All @@ -80,7 +85,8 @@ public boolean setRemainingRetries(int id, int newRetries) throws JSONException
String url = BASIC_OUTBOX_PATH + "/" + id;

HttpEntity<String> requestEntity =
prepareEntityFromBody("{\"remainingRetries\":" + newRetries + "}");
httpHeaderProvider.prepareEntityFromBodyForOutboxRestApi(
"{\"remainingRetries\":" + newRetries + "}");
ResponseEntity<String> answer =
this.restTemplate.exchange(url, HttpMethod.PATCH, requestEntity, String.class);

Expand All @@ -95,7 +101,8 @@ public boolean setRemainingRetriesForAll(int newRetries) throws JSONException {
String url = BASIC_OUTBOX_PATH + "?retries=0";

HttpEntity<String> requestEntity =
prepareEntityFromBody("{\"remainingRetries\":" + newRetries + "}");
httpHeaderProvider.prepareEntityFromBodyForOutboxRestApi(
"{\"remainingRetries\":" + newRetries + "}");
ResponseEntity<String> answer =
this.restTemplate.exchange(url, HttpMethod.PATCH, requestEntity, String.class);

Expand All @@ -104,16 +111,4 @@ public boolean setRemainingRetriesForAll(int newRetries) throws JSONException {
}
return false;
}

/**
* Helper method to create an HttpEntity from a provided body in JSON-format.
*
* @param jsonBody the body of the HttpEntity
* @return the created HttpEntity
*/
private HttpEntity<String> prepareEntityFromBody(String jsonBody) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return new HttpEntity<String>(jsonBody, headers);
}
}
9 changes: 9 additions & 0 deletions taskana-adapter-camunda-system-connector/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,20 @@
<artifactId>spring-boot-starter</artifactId>
<version>${version.spring.boot}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${version.spring.boot}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${version.spring.boot}</version>
</dependency>
<dependency>
<groupId>pro.taskana</groupId>
<artifactId>taskana-adapter</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ public static boolean isTaskNotExisting(
.append(camundaTaskId)
.toString();

HttpEntity<String> requestEntity =
httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi("{}");
HttpEntity<Void> requestEntity = httpHeaderProvider.prepareEntityFromBodyForCamundaRestApi();
try {
restTemplate.exchange(requestUrl, HttpMethod.GET, requestEntity, String.class);
} catch (HttpStatusCodeException ex) {
Expand Down
Loading

0 comments on commit 2ef249c

Please sign in to comment.