Skip to content

Commit 107caa9

Browse files
committed
Closes Taskana#2364 - Add Rerouting of Tasks in JAVA-API
1 parent 24fb36a commit 107caa9

File tree

13 files changed

+1172
-46
lines changed

13 files changed

+1172
-46
lines changed

common/taskana-common/src/main/java/pro/taskana/common/internal/util/ObjectAttributeChangeDetector.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public static <T> String determineChangesInAttributes(T oldObject, T newObject)
4040

4141
// this has to be checked after we deal with List data types, because
4242
// we want to allow different implementations of the List interface to work as well.
43-
if (!oldObject.getClass().equals(newObject.getClass())) {
43+
if (!oldObject.getClass().equals(newObject.getClass())
44+
&& !oldObject.getClass().isAssignableFrom(newObject.getClass())) {
4445
throw new SystemException(
4546
String.format(
4647
"The classes differ between the oldObject(%s) and newObject(%s). "

history/taskana-simplehistory-provider/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
</dependency>
3838

3939
<!-- test dependencies -->
40+
<dependency>
41+
<groupId>pro.taskana</groupId>
42+
<artifactId>taskana-test-api</artifactId>
43+
<version>${project.version}</version>
44+
<scope>test</scope>
45+
</dependency>
4046
<dependency>
4147
<groupId>pro.taskana</groupId>
4248
<artifactId>taskana-common-data</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
package acceptance.events.task;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import acceptance.events.task.CreateHistoryEventOnTaskRerouteAccTest.TaskRoutingProviderForDomainA;
6+
import java.lang.reflect.Field;
7+
import java.util.List;
8+
import org.apache.ibatis.session.SqlSessionManager;
9+
import org.json.JSONArray;
10+
import org.json.JSONObject;
11+
import org.junit.jupiter.api.BeforeAll;
12+
import org.junit.jupiter.api.Test;
13+
import org.junit.jupiter.api.extension.ExtendWith;
14+
import pro.taskana.classification.api.ClassificationService;
15+
import pro.taskana.classification.api.models.ClassificationSummary;
16+
import pro.taskana.common.api.TaskanaEngine;
17+
import pro.taskana.common.test.security.JaasExtension;
18+
import pro.taskana.common.test.security.WithAccessId;
19+
import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl;
20+
import pro.taskana.simplehistory.impl.TaskHistoryQueryImpl;
21+
import pro.taskana.simplehistory.impl.TaskanaHistoryEngineImpl;
22+
import pro.taskana.simplehistory.impl.task.TaskHistoryQueryMapper;
23+
import pro.taskana.spi.history.api.TaskanaHistory;
24+
import pro.taskana.spi.history.api.events.task.TaskHistoryEvent;
25+
import pro.taskana.spi.history.api.events.task.TaskHistoryEventType;
26+
import pro.taskana.spi.routing.api.TaskRoutingProvider;
27+
import pro.taskana.task.api.TaskService;
28+
import pro.taskana.task.api.models.Task;
29+
import pro.taskana.testapi.DefaultTestEntities;
30+
import pro.taskana.testapi.TaskanaInject;
31+
import pro.taskana.testapi.TaskanaIntegrationTest;
32+
import pro.taskana.testapi.WithServiceProvider;
33+
import pro.taskana.testapi.builder.TaskBuilder;
34+
import pro.taskana.testapi.builder.WorkbasketAccessItemBuilder;
35+
import pro.taskana.workbasket.api.WorkbasketPermission;
36+
import pro.taskana.workbasket.api.WorkbasketService;
37+
import pro.taskana.workbasket.api.models.Workbasket;
38+
import pro.taskana.workbasket.api.models.WorkbasketSummary;
39+
40+
@WithServiceProvider(
41+
serviceProviderInterface = TaskRoutingProvider.class,
42+
serviceProviders = TaskRoutingProviderForDomainA.class)
43+
@WithServiceProvider(
44+
serviceProviderInterface = TaskanaHistory.class,
45+
serviceProviders = SimpleHistoryServiceImpl.class)
46+
@TaskanaIntegrationTest
47+
@ExtendWith(JaasExtension.class)
48+
class CreateHistoryEventOnTaskRerouteAccTest {
49+
@TaskanaInject TaskanaEngine taskanaEngine;
50+
@TaskanaInject TaskService taskService;
51+
@TaskanaInject WorkbasketService workbasketService;
52+
@TaskanaInject ClassificationService classificationService;
53+
ClassificationSummary classificationSummary;
54+
WorkbasketSummary domainAWorkbasketSummary;
55+
WorkbasketSummary domainBWorkbasketSummary;
56+
Task task1;
57+
Task task2;
58+
Task task3;
59+
Task task4;
60+
private SimpleHistoryServiceImpl historyService = new SimpleHistoryServiceImpl();
61+
private TaskanaHistoryEngineImpl taskanaHistoryEngine;
62+
63+
@WithAccessId(user = "admin")
64+
@BeforeAll
65+
void setUp() throws Exception {
66+
taskanaHistoryEngine = TaskanaHistoryEngineImpl.createTaskanaEngine(taskanaEngine);
67+
historyService.initialize(taskanaEngine);
68+
classificationSummary =
69+
DefaultTestEntities.defaultTestClassification()
70+
.buildAndStoreAsSummary(classificationService);
71+
domainAWorkbasketSummary =
72+
DefaultTestEntities.defaultTestWorkbasket()
73+
.domain("DOMAIN_A")
74+
.buildAndStoreAsSummary(workbasketService);
75+
domainBWorkbasketSummary =
76+
DefaultTestEntities.defaultTestWorkbasket()
77+
.domain("DOMAIN_B")
78+
.buildAndStoreAsSummary(workbasketService);
79+
80+
task1 =
81+
TaskBuilder.newTask()
82+
.classificationSummary(classificationSummary)
83+
.workbasketSummary(domainAWorkbasketSummary)
84+
.primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build())
85+
.buildAndStore(taskService);
86+
task2 =
87+
TaskBuilder.newTask()
88+
.classificationSummary(classificationSummary)
89+
.workbasketSummary(domainAWorkbasketSummary)
90+
.primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build())
91+
.buildAndStore(taskService);
92+
task3 =
93+
TaskBuilder.newTask()
94+
.classificationSummary(classificationSummary)
95+
.workbasketSummary(domainBWorkbasketSummary)
96+
.primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build())
97+
.buildAndStore(taskService);
98+
99+
task4 =
100+
TaskBuilder.newTask()
101+
.classificationSummary(classificationSummary)
102+
.workbasketSummary(domainAWorkbasketSummary)
103+
.primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build())
104+
.buildAndStore(taskService);
105+
106+
WorkbasketAccessItemBuilder.newWorkbasketAccessItem()
107+
.workbasketId(domainAWorkbasketSummary.getId())
108+
.accessId("user-1-1")
109+
.permission(WorkbasketPermission.OPEN)
110+
.permission(WorkbasketPermission.READ)
111+
.permission(WorkbasketPermission.APPEND)
112+
.buildAndStore(workbasketService);
113+
114+
WorkbasketAccessItemBuilder.newWorkbasketAccessItem()
115+
.workbasketId(domainBWorkbasketSummary.getId())
116+
.accessId("user-1-1")
117+
.permission(WorkbasketPermission.OPEN)
118+
.permission(WorkbasketPermission.READ)
119+
.permission(WorkbasketPermission.APPEND)
120+
.buildAndStore(workbasketService);
121+
}
122+
123+
@WithAccessId(user = "admin")
124+
@Test
125+
void should_CreateRerouteHistoryEvent_When_TaskIsRerouted() throws Exception {
126+
historyService.deleteHistoryEventsByTaskIds(List.of(task4.getId()));
127+
TaskHistoryQueryMapper taskHistoryQueryMapper = getHistoryQueryMapper();
128+
List<TaskHistoryEvent> events =
129+
taskHistoryQueryMapper.queryHistoryEvents(
130+
(TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(task4.getId()));
131+
assertThat(events).isEmpty();
132+
taskService.rerouteTask(task4.getId());
133+
134+
events =
135+
taskHistoryQueryMapper.queryHistoryEvents(
136+
(TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(task4.getId()));
137+
138+
assertThat(events).hasSize(1);
139+
String eventType = events.get(0).getEventType();
140+
assertThat(eventType).isEqualTo(TaskHistoryEventType.REROUTED.getName());
141+
assertRerouteHistoryEvent(
142+
events.get(0).getId(),
143+
domainAWorkbasketSummary.getId(),
144+
domainBWorkbasketSummary.getId(),
145+
"admin");
146+
147+
historyService.deleteHistoryEventsByTaskIds(List.of(task4.getId()));
148+
}
149+
150+
@WithAccessId(user = "admin")
151+
@Test
152+
void should_CreateRerouteHistoryEvent_When_MultipleTasksAreRerouted() throws Exception {
153+
List<String> taskIds = List.of(task1.getId(), task2.getId(), task3.getId());
154+
historyService.deleteHistoryEventsByTaskIds(taskIds);
155+
TaskHistoryQueryMapper taskHistoryQueryMapper = getHistoryQueryMapper();
156+
157+
List<TaskHistoryEvent> events =
158+
taskHistoryQueryMapper.queryHistoryEvents(
159+
(TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(task1.getId()));
160+
assertThat(events).isEmpty();
161+
taskService.rerouteTasks(taskIds);
162+
163+
events =
164+
taskHistoryQueryMapper.queryHistoryEvents(
165+
(TaskHistoryQueryImpl)
166+
historyService.createTaskHistoryQuery().taskIdIn(taskIds.toArray(new String[0])));
167+
168+
assertThat(events)
169+
.extracting(TaskHistoryEvent::getTaskId)
170+
.containsExactlyInAnyOrderElementsOf(taskIds);
171+
172+
for (TaskHistoryEvent event : events) {
173+
if (event.getTaskId().equals(task1.getId())) {
174+
assertRerouteHistoryEvent(
175+
event.getId(),
176+
domainAWorkbasketSummary.getId(),
177+
domainBWorkbasketSummary.getId(),
178+
"admin");
179+
} else if (event.getTaskId().equals(task2.getId())) {
180+
assertRerouteHistoryEvent(
181+
event.getId(),
182+
domainAWorkbasketSummary.getId(),
183+
domainBWorkbasketSummary.getId(),
184+
"admin");
185+
} else {
186+
assertRerouteHistoryEvent(
187+
event.getId(),
188+
domainBWorkbasketSummary.getId(),
189+
domainAWorkbasketSummary.getId(),
190+
"admin");
191+
}
192+
}
193+
}
194+
195+
TaskHistoryQueryMapper getHistoryQueryMapper()
196+
throws NoSuchFieldException, IllegalAccessException {
197+
Field sessionManagerField = TaskanaHistoryEngineImpl.class.getDeclaredField("sessionManager");
198+
sessionManagerField.setAccessible(true);
199+
SqlSessionManager sqlSessionManager =
200+
(SqlSessionManager) sessionManagerField.get(taskanaHistoryEngine);
201+
202+
return sqlSessionManager.getMapper(TaskHistoryQueryMapper.class);
203+
}
204+
205+
private void assertRerouteHistoryEvent(
206+
String eventId, String expectedOldValue, String expectedNewValue, String expectedUser)
207+
throws Exception {
208+
TaskHistoryEvent event = historyService.getTaskHistoryEvent(eventId);
209+
assertThat(event.getDetails()).isNotNull();
210+
JSONArray changes = new JSONObject(event.getDetails()).getJSONArray("changes");
211+
assertThat(changes.length()).isPositive();
212+
boolean foundField = false;
213+
for (int i = 0; i < changes.length() && !foundField; i++) {
214+
JSONObject change = changes.getJSONObject(i);
215+
if (change.get("fieldName").equals("workbasketSummary")) {
216+
foundField = true;
217+
String oldWorkbasketStr = change.get("oldValue").toString();
218+
String newWorkbasketStr = change.get("newValue").toString();
219+
Workbasket oldWorkbasket = workbasketService.getWorkbasket(expectedOldValue);
220+
assertThat(oldWorkbasketStr)
221+
.isEqualTo(JSONObject.wrap(oldWorkbasket.asSummary()).toString());
222+
Workbasket newWorkbasket = workbasketService.getWorkbasket(expectedNewValue);
223+
assertThat(newWorkbasketStr)
224+
.isEqualTo(JSONObject.wrap(newWorkbasket.asSummary()).toString());
225+
}
226+
}
227+
assertThat(foundField).describedAs("changes do not contain field 'workbasketSummary'").isTrue();
228+
229+
assertThat(event.getId()).startsWith("THI:");
230+
assertThat(event.getOldValue()).isEqualTo(expectedOldValue);
231+
assertThat(event.getNewValue()).isEqualTo(expectedNewValue);
232+
assertThat(event.getUserId()).isEqualTo(expectedUser);
233+
assertThat(event.getEventType()).isEqualTo(TaskHistoryEventType.REROUTED.getName());
234+
}
235+
236+
class TaskRoutingProviderForDomainA implements TaskRoutingProvider {
237+
238+
@Override
239+
public void initialize(TaskanaEngine taskanaEngine) {}
240+
241+
@Override
242+
public String determineWorkbasketId(Task task) {
243+
if ("DOMAIN_A".equals(task.getDomain())) {
244+
return domainBWorkbasketSummary.getId();
245+
} else if ("DOMAIN_B".equals(task.getDomain())) {
246+
return domainAWorkbasketSummary.getId();
247+
}
248+
return null;
249+
}
250+
}
251+
}

0 commit comments

Comments
 (0)