chore: target Java 17 and document usage plus roadmap

Lower the compiler baseline to 17, rename listDefinitions to queryDefinitions, and align README/usage/roadmap with planned vs out-of-scope work.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
0264408
2026-09-15 10:55:30 +08:00
co-authored by Cursor
parent f3220fd0a0
commit 5795778112
20 changed files with 604 additions and 110 deletions
@@ -136,7 +136,7 @@ public final class DefaultOrdoEngine implements OrdoEngine {
ProcessStatus.RUNNING, now, null, context);
instanceRepository.insert(started);
record(events, started.id(), null, null, ProcessEventType.INSTANCE_STARTED, initiator, null, now);
enterStep(started, definition, definition.steps().getFirst(), now, queued, events);
enterStep(started, definition, definition.steps().get(0), now, queued, events);
return started;
});
finishCommittedWork(queued, events);
@@ -252,7 +252,7 @@ public final class DefaultOrdoEngine implements OrdoEngine {
}
@Override
public synchronized Page<ProcessDefinition> listDefinitions(PageRequest pageRequest) {
public synchronized Page<ProcessDefinition> queryDefinitions(PageRequest pageRequest) {
Objects.requireNonNull(pageRequest, "pageRequest must not be null");
return definitionRepository.findAll(pageRequest);
}
@@ -141,8 +141,8 @@ public final class InMemoryOrdoEngine implements OrdoEngine {
}
@Override
public Page<ProcessDefinition> listDefinitions(PageRequest pageRequest) {
return delegate.listDefinitions(pageRequest);
public Page<ProcessDefinition> queryDefinitions(PageRequest pageRequest) {
return delegate.queryDefinitions(pageRequest);
}
@Override
@@ -57,7 +57,7 @@ class InMemoryOrdoEngineTest {
@Test
void completesASequentialApprovalProcess() {
var instance = engine.start("leave", "alice");
ApprovalTask managerTask = engine.findTasks(instance.id()).getFirst();
ApprovalTask managerTask = engine.findTasks(instance.id()).get(0);
assertEquals(TaskStatus.APPROVED, engine.approve(managerTask.id(), "maria").status());
ApprovalTask hrTask = engine.findTasks(instance.id()).get(1);
@@ -70,7 +70,7 @@ class InMemoryOrdoEngineTest {
@Test
void rejectionTerminatesTheProcess() {
var instance = engine.start("leave", "alice");
ApprovalTask task = engine.findTasks(instance.id()).getFirst();
ApprovalTask task = engine.findTasks(instance.id()).get(0);
ApprovalTask rejectedTask = engine.reject(task.id(), "maria", "Insufficient leave balance");
@@ -86,7 +86,7 @@ class InMemoryOrdoEngineTest {
@Test
void rejectsDuplicateAndUnauthorizedOperations() {
var instance = engine.start("leave", "alice");
ApprovalTask task = engine.findTasks(instance.id()).getFirst();
ApprovalTask task = engine.findTasks(instance.id()).get(0);
assertThrows(UnauthorizedTaskOperationException.class, () -> engine.approve(task.id(), "mallory"));
engine.approve(task.id(), "maria");
@@ -108,7 +108,7 @@ class InMemoryOrdoEngineTest {
ApprovalStep.single("director", "Director approval", "diana"))));
var instance = empty.start("expense", "alice");
assertEquals("diana", empty.findTasks(instance.id()).getFirst().assignee());
assertEquals("diana", empty.findTasks(instance.id()).get(0).assignee());
}
@Test
@@ -117,7 +117,7 @@ class InMemoryOrdoEngineTest {
ApprovalStep.single("director", "Director approval", "diana"))));
var instance = engine.start("leave", "alice");
ApprovalTask task = engine.findTasks(instance.id()).getFirst();
ApprovalTask task = engine.findTasks(instance.id()).get(0);
assertEquals("director", task.stepId());
assertEquals("diana", task.assignee());
}
@@ -132,19 +132,19 @@ class InMemoryOrdoEngineTest {
@Test
void replaceSucceedsAfterInstancesReachATerminalStatus() {
var instance = engine.start("leave", "alice");
engine.reject(engine.findTasks(instance.id()).getFirst().id(), "maria");
engine.reject(engine.findTasks(instance.id()).get(0).id(), "maria");
engine.replace(ProcessDefinition.linear("leave", "Leave request v2", List.of(
ApprovalStep.single("director", "Director approval", "diana"))));
var next = engine.start("leave", "bob");
assertEquals("diana", engine.findTasks(next.id()).getFirst().assignee());
assertEquals("diana", engine.findTasks(next.id()).get(0).assignee());
}
@Test
void initiatorCanWithdrawWhileALaterStepIsPending() {
var instance = engine.start("leave", "alice");
engine.approve(engine.findTasks(instance.id()).getFirst().id(), "maria");
engine.approve(engine.findTasks(instance.id()).get(0).id(), "maria");
ProcessInstance withdrawn = engine.withdraw(instance.id(), "alice", "changed plans");
@@ -172,7 +172,7 @@ class InMemoryOrdoEngineTest {
() -> engine.withdraw(instance.id(), "mallory"));
assertThrows(InstanceNotFoundException.class, () -> engine.withdraw("missing", "alice"));
engine.reject(engine.findTasks(instance.id()).getFirst().id(), "maria");
engine.reject(engine.findTasks(instance.id()).get(0).id(), "maria");
assertThrows(InstanceAlreadyCompletedException.class, () -> engine.withdraw(instance.id(), "alice"));
}
@@ -182,7 +182,7 @@ class InMemoryOrdoEngineTest {
assertThrows(DefinitionNotFoundException.class, () -> engine.start(" ", "alice"));
var instance = engine.start("leave", "alice");
ApprovalTask task = engine.findTasks(instance.id()).getFirst();
ApprovalTask task = engine.findTasks(instance.id()).get(0);
assertThrows(IllegalArgumentException.class, () -> engine.approve(task.id(), " "));
assertThrows(IllegalArgumentException.class, () -> engine.reject(task.id(), " "));
}
@@ -191,7 +191,7 @@ class InMemoryOrdoEngineTest {
void keepsSeparateInstancesIndependent() {
var aliceInstance = engine.start("leave", "alice");
var bobInstance = engine.start("leave", "bob");
ApprovalTask aliceTask = engine.findTasks(aliceInstance.id()).getFirst();
ApprovalTask aliceTask = engine.findTasks(aliceInstance.id()).get(0);
engine.approve(aliceTask.id(), "maria");
@@ -199,7 +199,7 @@ class InMemoryOrdoEngineTest {
assertEquals(1, engine.findTasks(bobInstance.id()).size());
assertEquals(ProcessStatus.RUNNING, engine.findInstance(aliceInstance.id()).orElseThrow().status());
assertEquals(ProcessStatus.RUNNING, engine.findInstance(bobInstance.id()).orElseThrow().status());
assertEquals("maria", engine.findTasks(bobInstance.id()).getFirst().assignee());
assertEquals("maria", engine.findTasks(bobInstance.id()).get(0).assignee());
assertTrue(engine.findTasks("missing-instance").isEmpty());
}
@@ -207,14 +207,14 @@ class InMemoryOrdoEngineTest {
void findsOnlyCurrentPendingTasksByAssigneeAndInstance() {
var aliceInstance = engine.start("leave", "alice");
var bobInstance = engine.start("leave", "bob");
ApprovalTask aliceManagerTask = engine.findPendingTasksByInstanceId(aliceInstance.id()).getFirst();
ApprovalTask aliceManagerTask = engine.findPendingTasksByInstanceId(aliceInstance.id()).get(0);
assertEquals(2, engine.findPendingTasksByAssignee("maria").size());
assertEquals(List.of(aliceManagerTask), engine.findPendingTasksByInstanceId(aliceInstance.id()));
assertTrue(engine.findPendingTasksByAssignee("henry").isEmpty());
engine.approve(aliceManagerTask.id(), "maria");
ApprovalTask hrTask = engine.findPendingTasksByInstanceId(aliceInstance.id()).getFirst();
ApprovalTask hrTask = engine.findPendingTasksByInstanceId(aliceInstance.id()).get(0);
assertEquals("hr", hrTask.stepId());
assertEquals("henry", hrTask.assignee());
@@ -230,7 +230,7 @@ class InMemoryOrdoEngineTest {
@Test
void recordsApprovalAuditDataAndLeavesPendingTasksWithoutAnAction() {
var instance = engine.start("leave", "alice");
ApprovalTask managerTask = engine.findPendingTasksByInstanceId(instance.id()).getFirst();
ApprovalTask managerTask = engine.findPendingTasksByInstanceId(instance.id()).get(0);
assertNull(managerTask.action());
ApprovalTask approvedTask = engine.approve(managerTask.id(), "maria", " Approved for the requested dates. ");
@@ -262,11 +262,11 @@ class InMemoryOrdoEngineTest {
"manager", "david",
"hr", "helena"
)));
ApprovalTask managerTask = contextAwareEngine.findPendingTasksByInstanceId(instance.id()).getFirst();
ApprovalTask managerTask = contextAwareEngine.findPendingTasksByInstanceId(instance.id()).get(0);
assertEquals("david", managerTask.assignee());
contextAwareEngine.approve(managerTask.id(), "david");
assertEquals("helena", contextAwareEngine.findPendingTasksByInstanceId(instance.id()).getFirst().assignee());
assertEquals("helena", contextAwareEngine.findPendingTasksByInstanceId(instance.id()).get(0).assignee());
assertEquals("david", instance.context().value("manager").orElseThrow());
}
@@ -293,7 +293,7 @@ class InMemoryOrdoEngineTest {
.filter(t -> t.id().equals(mikeTask.id())).findFirst().orElseThrow().status());
assertThrows(TaskAlreadyCompletedException.class, () -> anyEngine.approve(mikeTask.id(), "mike"));
ApprovalTask hrTask = anyEngine.findPendingTasksByInstanceId(instance.id()).getFirst();
ApprovalTask hrTask = anyEngine.findPendingTasksByInstanceId(instance.id()).get(0);
assertEquals("hr", hrTask.stepId());
anyEngine.approve(hrTask.id(), "henry");
assertEquals(ProcessStatus.APPROVED, anyEngine.findInstance(instance.id()).orElseThrow().status());
@@ -338,7 +338,7 @@ class InMemoryOrdoEngineTest {
assertEquals(ProcessStatus.RUNNING, allEngine.findInstance(instance.id()).orElseThrow().status());
allEngine.approve(mikeTask.id(), "mike");
ApprovalTask hrTask = allEngine.findPendingTasksByInstanceId(instance.id()).getFirst();
ApprovalTask hrTask = allEngine.findPendingTasksByInstanceId(instance.id()).get(0);
assertEquals("hr", hrTask.stepId());
allEngine.approve(hrTask.id(), "henry");
assertEquals(ProcessStatus.APPROVED, allEngine.findInstance(instance.id()).orElseThrow().status());
@@ -385,13 +385,13 @@ class InMemoryOrdoEngineTest {
StepTransition.end("director"))));
var high = routingEngine.start("expense", "alice", new ProcessContext(Map.of("amount", 2500)));
routingEngine.approve(routingEngine.findPendingTasksByInstanceId(high.id()).getFirst().id(), "maria");
assertEquals("director", routingEngine.findPendingTasksByInstanceId(high.id()).getFirst().stepId());
routingEngine.approve(routingEngine.findPendingTasksByInstanceId(high.id()).getFirst().id(), "diana");
routingEngine.approve(routingEngine.findPendingTasksByInstanceId(high.id()).get(0).id(), "maria");
assertEquals("director", routingEngine.findPendingTasksByInstanceId(high.id()).get(0).stepId());
routingEngine.approve(routingEngine.findPendingTasksByInstanceId(high.id()).get(0).id(), "diana");
assertEquals(ProcessStatus.APPROVED, routingEngine.findInstance(high.id()).orElseThrow().status());
var low = routingEngine.start("expense", "bob", new ProcessContext(Map.of("amount", 200)));
routingEngine.approve(routingEngine.findPendingTasksByInstanceId(low.id()).getFirst().id(), "maria");
routingEngine.approve(routingEngine.findPendingTasksByInstanceId(low.id()).get(0).id(), "maria");
assertEquals(ProcessStatus.APPROVED, routingEngine.findInstance(low.id()).orElseThrow().status());
assertTrue(routingEngine.findPendingTasksByInstanceId(low.id()).isEmpty());
}
@@ -411,10 +411,10 @@ class InMemoryOrdoEngineTest {
StepTransition.end("hr"))));
var instance = actionEngine.start("leave", "alice");
actionEngine.approve(actionEngine.findPendingTasksByInstanceId(instance.id()).getFirst().id(), "maria");
actionEngine.approve(actionEngine.findPendingTasksByInstanceId(instance.id()).get(0).id(), "maria");
assertEquals(List.of("leave-approved-mail"), executed);
ApprovalTask hrTask = actionEngine.findPendingTasksByInstanceId(instance.id()).getFirst();
ApprovalTask hrTask = actionEngine.findPendingTasksByInstanceId(instance.id()).get(0);
assertEquals("hr", hrTask.stepId());
assertEquals(ProcessStatus.RUNNING, actionEngine.findInstance(instance.id()).orElseThrow().status());
}
@@ -433,7 +433,7 @@ class InMemoryOrdoEngineTest {
StepTransition.end("notify"))));
var instance = actionEngine.start("leave", "alice");
actionEngine.approve(actionEngine.findPendingTasksByInstanceId(instance.id()).getFirst().id(), "maria");
actionEngine.approve(actionEngine.findPendingTasksByInstanceId(instance.id()).get(0).id(), "maria");
assertEquals(ProcessStatus.APPROVED, actionEngine.findInstance(instance.id()).orElseThrow().status());
}
@@ -451,7 +451,7 @@ class InMemoryOrdoEngineTest {
var instance = actionEngine.start("leave", "alice");
assertEquals(List.of("leave-submitted-mail"), executed);
assertEquals("manager", actionEngine.findPendingTasksByInstanceId(instance.id()).getFirst().stepId());
assertEquals("manager", actionEngine.findPendingTasksByInstanceId(instance.id()).get(0).stepId());
assertEquals(ProcessStatus.RUNNING, instance.status());
}
@@ -463,7 +463,7 @@ class InMemoryOrdoEngineTest {
List.of(StepTransition.endWhen("manager", "never", 0))));
var instance = routingEngine.start("expense", "alice");
ApprovalTask task = routingEngine.findPendingTasksByInstanceId(instance.id()).getFirst();
ApprovalTask task = routingEngine.findPendingTasksByInstanceId(instance.id()).get(0);
assertThrows(NoRouteFoundException.class, () -> routingEngine.approve(task.id(), "maria"));
}
@@ -476,12 +476,12 @@ class InMemoryOrdoEngineTest {
Page<ApprovalTask> byAssignee = engine.queryTasks(TaskQuery.any().withAssignee("maria"), new PageRequest(0, 10));
assertEquals(1, byAssignee.totalElements());
assertEquals("maria", byAssignee.content().getFirst().assignee());
assertEquals("maria", byAssignee.content().get(0).assignee());
Page<ApprovalTask> byDefinition = engine.queryTasks(TaskQuery.any().withDefinitionId("leave"),
new PageRequest(0, 10));
assertEquals(1, byDefinition.totalElements());
assertEquals(leaveInstance.id(), byDefinition.content().getFirst().instanceId());
assertEquals(leaveInstance.id(), byDefinition.content().get(0).instanceId());
Page<ApprovalTask> firstPage = engine.queryTasks(TaskQuery.any(), new PageRequest(0, 1));
assertEquals(2, firstPage.totalElements());
@@ -499,20 +499,20 @@ class InMemoryOrdoEngineTest {
Page<ProcessInstance> runningOnly = engine.queryInstances(
InstanceQuery.any().withStatus(ProcessStatus.RUNNING), new PageRequest(0, 10));
assertEquals(1, runningOnly.totalElements());
assertEquals(running.id(), runningOnly.content().getFirst().id());
assertEquals(running.id(), runningOnly.content().get(0).id());
Page<ProcessInstance> byInitiator = engine.queryInstances(InstanceQuery.any().withInitiator("bob"),
new PageRequest(0, 10));
assertEquals(1, byInitiator.totalElements());
assertEquals(ProcessStatus.WITHDRAWN, byInitiator.content().getFirst().status());
assertEquals(ProcessStatus.WITHDRAWN, byInitiator.content().get(0).status());
}
@Test
void listDefinitionsPaginatesRegisteredDefinitions() {
void queryDefinitionsPaginatesRegisteredDefinitions() {
engine.register(ProcessDefinition.linear("expense", "Expense request", List.of(
ApprovalStep.single("finance", "Finance approval", "frank"))));
Page<ProcessDefinition> all = engine.listDefinitions(new PageRequest(0, 10));
Page<ProcessDefinition> all = engine.queryDefinitions(new PageRequest(0, 10));
assertEquals(2, all.totalElements());
assertEquals(List.of("expense", "leave"), all.content().stream().map(ProcessDefinition::id).toList());
}
@@ -529,7 +529,7 @@ class InMemoryOrdoEngineTest {
ApprovalTask mariaTask = anyEngine.findTasks(instance.id()).stream()
.filter(task -> task.assignee().equals("maria")).findFirst().orElseThrow();
anyEngine.approve(mariaTask.id(), "maria");
anyEngine.approve(anyEngine.findPendingTasksByInstanceId(instance.id()).getFirst().id(), "henry");
anyEngine.approve(anyEngine.findPendingTasksByInstanceId(instance.id()).get(0).id(), "henry");
List<ProcessEventType> types = anyEngine.queryHistory(instance.id(), new PageRequest(0, 50)).content()
.stream().map(ProcessEvent::type).toList();
@@ -574,7 +574,7 @@ class InMemoryOrdoEngineTest {
ApprovalStep.single("manager", "Manager approval", "maria"))));
var instance = listening.start("leave", "alice");
listening.approve(listening.findPendingTasksByInstanceId(instance.id()).getFirst().id(), "maria");
listening.approve(listening.findPendingTasksByInstanceId(instance.id()).get(0).id(), "maria");
assertEquals(ProcessStatus.APPROVED, listening.findInstance(instance.id()).orElseThrow().status());
assertEquals(List.of(
@@ -601,7 +601,7 @@ class InMemoryOrdoEngineTest {
StepTransition.end("fail"))));
var instance = actionEngine.start("leave", "alice");
actionEngine.approve(actionEngine.findPendingTasksByInstanceId(instance.id()).getFirst().id(), "maria");
actionEngine.approve(actionEngine.findPendingTasksByInstanceId(instance.id()).get(0).id(), "maria");
assertEquals(ProcessStatus.APPROVED, actionEngine.findInstance(instance.id()).orElseThrow().status());
List<ActionExecution> executions = actionEngine.queryActionExecutions(instance.id(), new PageRequest(0, 10))