Skip to content

Commit

Permalink
Closes Taskana#2364 - Add Rerouting of Tasks in JAVA-API
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesrdi committed Aug 31, 2023
1 parent 44c0237 commit bdf7b3a
Show file tree
Hide file tree
Showing 14 changed files with 1,048 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ public static <T> String determineChangesInAttributes(T oldObject, T newObject)

// this has to be checked after we deal with List data types, because
// we want to allow different implementations of the List interface to work as well.
if (!oldObject.getClass().equals(newObject.getClass())) {
throw new SystemException(
String.format(
"The classes differ between the oldObject(%s) and newObject(%s). "
+ "In order to detect changes properly they should not differ.",
oldObject.getClass().getName(), newObject.getClass().getName()));
if (!oldObject.getClass().equals(newObject.getClass()) && !oldObject.getClass().isAssignableFrom(newObject.getClass())) {
throw new SystemException(
String.format(
"The classes differ between the oldObject(%s) and newObject(%s). "
+ "In order to detect changes properly they should not differ.",
oldObject.getClass().getName(), newObject.getClass().getName()));

}

List<JSONObject> changedAttributes =
Expand Down
6 changes: 6 additions & 0 deletions history/taskana-simplehistory-provider/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
</dependency>

<!-- test dependencies -->
<dependency>
<groupId>pro.taskana</groupId>
<artifactId>taskana-test-api</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>pro.taskana</groupId>
<artifactId>taskana-common-data</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
package acceptance.events.task;

import static org.assertj.core.api.Assertions.assertThat;

import acceptance.events.task.CreateHistoryEventOnTaskRerouteAccTest.TaskRoutingProviderForDomainA;
import java.lang.reflect.Field;
import java.util.List;
import org.apache.ibatis.session.SqlSessionManager;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import pro.taskana.classification.api.ClassificationService;
import pro.taskana.classification.api.models.ClassificationSummary;
import pro.taskana.common.api.TaskanaEngine;
import pro.taskana.common.test.security.JaasExtension;
import pro.taskana.common.test.security.WithAccessId;
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
import pro.taskana.simplehistory.impl.TaskHistoryQueryImpl;
import pro.taskana.simplehistory.impl.TaskanaHistoryEngineImpl;
import pro.taskana.simplehistory.impl.task.TaskHistoryQueryMapper;
import pro.taskana.spi.history.api.TaskanaHistory;
import pro.taskana.spi.history.api.events.task.TaskHistoryEvent;
import pro.taskana.spi.history.api.events.task.TaskHistoryEventType;
import pro.taskana.spi.routing.api.TaskRoutingProvider;
import pro.taskana.task.api.TaskService;
import pro.taskana.task.api.models.Task;
import pro.taskana.testapi.DefaultTestEntities;
import pro.taskana.testapi.TaskanaInject;
import pro.taskana.testapi.TaskanaIntegrationTest;
import pro.taskana.testapi.WithServiceProvider;
import pro.taskana.testapi.builder.TaskBuilder;
import pro.taskana.testapi.builder.WorkbasketAccessItemBuilder;
import pro.taskana.workbasket.api.WorkbasketPermission;
import pro.taskana.workbasket.api.WorkbasketService;
import pro.taskana.workbasket.api.models.Workbasket;
import pro.taskana.workbasket.api.models.WorkbasketSummary;

@WithServiceProvider(
serviceProviderInterface = TaskRoutingProvider.class,
serviceProviders = TaskRoutingProviderForDomainA.class)
@WithServiceProvider(
serviceProviderInterface = TaskanaHistory.class,
serviceProviders = SimpleHistoryServiceImpl.class)
@TaskanaIntegrationTest
@ExtendWith(JaasExtension.class)
class CreateHistoryEventOnTaskRerouteAccTest {
@TaskanaInject TaskanaEngine taskanaEngine;
@TaskanaInject TaskService taskService;
@TaskanaInject WorkbasketService workbasketService;
@TaskanaInject ClassificationService classificationService;
ClassificationSummary classificationSummary;
WorkbasketSummary domainAWorkbasketSummary;
WorkbasketSummary domainBWorkbasketSummary;
Task task1;
Task task2;
Task task3;
private SimpleHistoryServiceImpl historyService = new SimpleHistoryServiceImpl();
private TaskanaHistoryEngineImpl taskanaHistoryEngine;

@WithAccessId(user = "admin")
@BeforeAll
void setUp() throws Exception {
taskanaHistoryEngine = TaskanaHistoryEngineImpl.createTaskanaEngine(taskanaEngine);
historyService.initialize(taskanaEngine);
classificationSummary =
DefaultTestEntities.defaultTestClassification()
.buildAndStoreAsSummary(classificationService);
domainAWorkbasketSummary =
DefaultTestEntities.defaultTestWorkbasket()
.domain("DOMAIN_A")
.buildAndStoreAsSummary(workbasketService);
domainBWorkbasketSummary =
DefaultTestEntities.defaultTestWorkbasket()
.domain("DOMAIN_B")
.buildAndStoreAsSummary(workbasketService);

task1 =
TaskBuilder.newTask()
.classificationSummary(classificationSummary)
.workbasketSummary(domainAWorkbasketSummary)
.primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build())
.buildAndStore(taskService);
task2 =
TaskBuilder.newTask()
.classificationSummary(classificationSummary)
.workbasketSummary(domainAWorkbasketSummary)
.primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build())
.buildAndStore(taskService);
task3 =
TaskBuilder.newTask()
.classificationSummary(classificationSummary)
.workbasketSummary(domainBWorkbasketSummary)
.primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build())
.buildAndStore(taskService);

WorkbasketAccessItemBuilder.newWorkbasketAccessItem()
.workbasketId(domainAWorkbasketSummary.getId())
.accessId("user-1-1")
.permission(WorkbasketPermission.OPEN)
.permission(WorkbasketPermission.READ)
.permission(WorkbasketPermission.APPEND)
.buildAndStore(workbasketService);

WorkbasketAccessItemBuilder.newWorkbasketAccessItem()
.workbasketId(domainBWorkbasketSummary.getId())
.accessId("user-1-1")
.permission(WorkbasketPermission.OPEN)
.permission(WorkbasketPermission.READ)
.permission(WorkbasketPermission.APPEND)
.buildAndStore(workbasketService);
}

@WithAccessId(user = "admin")
@Test
void should_CreateRerouteHistoryEvent_When_TaskIsRerouted() throws Exception {
historyService.deleteHistoryEventsByTaskIds(List.of(task1.getId()));
TaskHistoryQueryMapper taskHistoryQueryMapper = getHistoryQueryMapper();
List<TaskHistoryEvent> events =
taskHistoryQueryMapper.queryHistoryEvents(
(TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(task1.getId()));
assertThat(events).hasSize(0);
taskService.rerouteTask(task1.getId());

events =
taskHistoryQueryMapper.queryHistoryEvents(
(TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(task1.getId()));

assertThat(events).hasSize(1);
String eventType = events.get(0).getEventType();
assertThat(eventType).isEqualTo(TaskHistoryEventType.REROUTED.getName());
assertRerouteHistoryEvent(
events.get(0).getId(),
domainAWorkbasketSummary.getId(),
domainBWorkbasketSummary.getId(),
"admin");

historyService.deleteHistoryEventsByTaskIds(List.of(task1.getId()));
}

@WithAccessId(user = "admin")
@Test
void should_CreateRerouteHistoryEvent_When_MultipleTasksAreRerouted() throws Exception {
List<String> taskIds = List.of(task1.getId(), task2.getId(), task3.getId());
historyService.deleteHistoryEventsByTaskIds(taskIds);
TaskHistoryQueryMapper taskHistoryQueryMapper = getHistoryQueryMapper();

List<TaskHistoryEvent> events =
taskHistoryQueryMapper.queryHistoryEvents(
(TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(task1.getId()));
assertThat(events).hasSize(0);
taskService.rerouteTasks(taskIds);

events =
taskHistoryQueryMapper.queryHistoryEvents(
(TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(taskIds.toArray(new String[0])));

assertThat(events)
.extracting(TaskHistoryEvent::getTaskId)
.containsExactlyInAnyOrderElementsOf(taskIds);

for (TaskHistoryEvent event : events ) {
if(event.getTaskId().equals(task1.getId())){
assertRerouteHistoryEvent(event.getId(), domainAWorkbasketSummary.getId(), domainBWorkbasketSummary.getId(), "admin");
}else if(event.getTaskId().equals(task2.getId())){
assertRerouteHistoryEvent(event.getId(), domainAWorkbasketSummary.getId(), domainBWorkbasketSummary.getId(), "admin");
}else{
assertRerouteHistoryEvent(event.getId(), domainBWorkbasketSummary.getId(), domainAWorkbasketSummary.getId(), "admin");
}
}
}

TaskHistoryQueryMapper getHistoryQueryMapper()
throws NoSuchFieldException, IllegalAccessException {
Field sessionManagerField = TaskanaHistoryEngineImpl.class.getDeclaredField("sessionManager");
sessionManagerField.setAccessible(true);
SqlSessionManager sqlSessionManager =
(SqlSessionManager) sessionManagerField.get(taskanaHistoryEngine);

return sqlSessionManager.getMapper(TaskHistoryQueryMapper.class);
}

private void assertRerouteHistoryEvent(
String eventId, String expectedOldValue, String expectedNewValue, String expectedUser)
throws Exception {
TaskHistoryEvent event = historyService.getTaskHistoryEvent(eventId);
assertThat(event.getDetails()).isNotNull();
JSONArray changes = new JSONObject(event.getDetails()).getJSONArray("changes");
assertThat(changes.length()).isPositive();
boolean foundField = false;
for (int i = 0; i < changes.length() && !foundField; i++) {
JSONObject change = changes.getJSONObject(i);
if (change.get("fieldName").equals("workbasketSummary")) {
foundField = true;
String oldWorkbasketStr = change.get("oldValue").toString();
String newWorkbasketStr = change.get("newValue").toString();
Workbasket oldWorkbasket = workbasketService.getWorkbasket(expectedOldValue);
assertThat(oldWorkbasketStr)
.isEqualTo(JSONObject.wrap(oldWorkbasket.asSummary()).toString());
Workbasket newWorkbasket = workbasketService.getWorkbasket(expectedNewValue);
assertThat(newWorkbasketStr)
.isEqualTo(JSONObject.wrap(newWorkbasket.asSummary()).toString());
}
}
assertThat(foundField).describedAs("changes do not contain field 'workbasketSummary'").isTrue();

assertThat(event.getId()).startsWith("THI:");
assertThat(event.getOldValue()).isEqualTo(expectedOldValue);
assertThat(event.getNewValue()).isEqualTo(expectedNewValue);
assertThat(event.getUserId()).isEqualTo(expectedUser);
assertThat(event.getEventType()).isEqualTo(TaskHistoryEventType.REROUTED.getName());
}

class TaskRoutingProviderForDomainA implements TaskRoutingProvider {

@Override
public void initialize(TaskanaEngine taskanaEngine) {}

@Override
public String determineWorkbasketId(Task task) {
if ("DOMAIN_A".equals(task.getDomain())) {
return domainBWorkbasketSummary.getId();
} else if ("DOMAIN_B".equals(task.getDomain())) {
return domainAWorkbasketSummary.getId();
}
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/" xmlns:dmndi="https://www.omg.org/spec/DMN/20191111/DMNDI/" xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/" xmlns:ns0="http://camunda.org/schema/1.0/dmn" id="definitions" name="definitions" namespace="http://camunda.org/schema/1.0/dmn" exporter="Camunda Modeler" exporterVersion="5.12.1">
<decision id="workbasketRouting" name="Workbasket Routing">
<decisionTable id="workbasketRouting_decisionTable" hitPolicy="FIRST">
<input id="workbasketRouting_decisionTable-input_2" label="porValue" ns0:inputVariable="input">
<inputExpression id="workbasketRouting_decisionTable-inputExpression_2" typeRef="string">
<text>task.primaryObjRef.value</text>
</inputExpression>
</input>
<input id="InputClause_1qkek3h" label="porType" ns0:inputVariable="input">
<inputExpression id="LiteralExpression_1k84ufl" typeRef="string">
<text>task.primaryObjRef.type</text>
</inputExpression>
</input>
<output id="workbasketRouting_decisionTable-output_workbasketKey" label="Workbasket key" name="workbasketKey" typeRef="string" />
<output id="workbasketRouting_decisionTable-output_domain" label="Domain" name="domain" typeRef="string" />
<rule id="workbasketRouting_decisionTable-rule_0">
<inputEntry id="workbasketRouting_decisionTable-rule_0-inputEntry_2">
<text>"00000001"</text>
</inputEntry>
<inputEntry id="UnaryTests_0n5ac31">
<text>"MyType1"</text>
</inputEntry>
<outputEntry id="workbasketRouting_decisionTable-rule_0-outputEntry_workbasketKey">
<text>"GPK_KSC"</text>
</outputEntry>
<outputEntry id="workbasketRouting_decisionTable-rule_0-outputEntry_domain">
<text>"DOMAIN_A"</text>
</outputEntry>
</rule>
<rule id="DecisionRule_0ua6ja6">
<inputEntry id="UnaryTests_1kdwhvv">
<text>"00000001"</text>
</inputEntry>
<inputEntry id="UnaryTests_03hbryc">
<text>"none"</text>
</inputEntry>
<outputEntry id="workbasketRouting_decisionTable-rule_1-outputEntry_workbasketKey">
<text>"GPK_KSC_1"</text>
</outputEntry>
<outputEntry id="workbasketRouting_decisionTable-rule_1-outputEntry_domain">
<text>"DOMAIN_A"</text>
</outputEntry>
</rule>
<rule id="DecisionRule_0elr8ov">
<inputEntry id="UnaryTests_0n7qv3k">
<text>"none"</text>
</inputEntry>
<inputEntry id="UnaryTests_0jwi2ra">
<text>"MyType1"</text>
</inputEntry>
<outputEntry id="workbasketRouting_decisionTable-rule_2-outputEntry_workbasketKey">
<text>"GPK_KSC_2"</text>
</outputEntry>
<outputEntry id="workbasketRouting_decisionTable-rule_2-outputEntry_domain">
<text>"DOMAIN_A"</text>
</outputEntry>
</rule>
</decisionTable>
</decision>
<dmndi:DMNDI>
<dmndi:DMNDiagram id="DMNDiagram_1u50wbl">
<dmndi:DMNShape id="DMNShape_01ctrg1" dmnElementRef="workbasketRouting">
<dc:Bounds height="80" width="180" x="150" y="150" />
</dmndi:DMNShape>
</dmndi:DMNDiagram>
</dmndi:DMNDI>
</definitions>
Loading

0 comments on commit bdf7b3a

Please sign in to comment.