Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ build/
### DEV
_tmp/
.repository/
.claude/logs/
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ If you want to try the API, please refer to one of the adapter implementations m
| Start Process by definition | ✅ | ✅ | ✅ | ✅ |
| Start Process by definition at | ✅ | ✅ | ✅ | ✅ |
| Start Process by message | ✅ | ✅ | ✅ | ✅ |
| Start Process by message at | 🚧 | 🚧 | 🚧 | ❌ |
| Correlate message | ✅ | ✅ | ✅ | ✅ |
| Send signal | ✅ | ✅ | ✅ | ✅ |
| Subscribe to task | ✅ | ✅ | ✅ | ✅ |
Expand All @@ -62,6 +63,8 @@ If you want to try the API, please refer to one of the adapter implementations m
| Complete service task by error | ✅ | ✅ | ✅ | ✅ |
| Fail service task | ✅ | ✅ | ✅ | ✅ |

*✅ supported · 🚧 in development · ❌ not supported*

## Process Engine Worker

If you are using the Process Engine API to provide external task workers using Spring Boot, there is a library with improved support for it:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package dev.bpmcrafters.processengineapi.process

import dev.bpmcrafters.processengineapi.PayloadSupplier

/**
* Command to start a new process instance by message at a specific element.
* Useful for processes that have no plain (none) start event and are entered
* only via one or multiple message start events.
* @since 1.7
*/
data class StartProcessByMessageAtElementCmd(
/**
* Name of the message.
*/
val messageName: String,
/**
* ID of the element to start the process at.
*/
val elementId: String,
/**
* Payload supplier to pass to the new process instance.
*/
val payloadSupplier: PayloadSupplier,
/**
* Restrictions applied for this start command.
*/
val restrictions: Map<String, String> = emptyMap()
) : StartProcessCommand, PayloadSupplier by payloadSupplier {
/**
* Constructs a start command with a message name, element ID, payload, and restrictions.
* @param messageName message name.
* @param elementId element ID to start the process at.
* @param payload payload to use.
* @param restrictions restrictions for the start command.
*/
constructor(messageName: String, elementId: String, payload: Map<String, Any?>, restrictions: Map<String, String>) : this(
messageName = messageName,
elementId = elementId,
payloadSupplier = PayloadSupplier { payload },
restrictions = restrictions
)
/**
* Constructs a start command with a message name, element ID, and payload.
* @param messageName message name.
* @param elementId element ID to start the process at.
* @param payload payload to use.
*/
constructor(messageName: String, elementId: String, payload: Map<String, Any?>) : this(
messageName = messageName,
elementId = elementId,
payloadSupplier = PayloadSupplier { payload } ,
restrictions = mapOf()
)

/**
* Constructs a start command with message name, element ID, and no payload.
* @param messageName message name.
* @param elementId element ID to start the process at.
*/
constructor(messageName: String, elementId: String) : this(
messageName = messageName,
elementId = elementId,
payload = mapOf(),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dev.bpmcrafters.processengineapi.process

import dev.bpmcrafters.processengineapi.CommonRestrictions
import dev.bpmcrafters.processengineapi.PayloadSupplier
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

internal class StartProcessByMessageAtElementCmdTest {

@Test
fun `should create command with payload supplier and restrictions`() {
val payload = mapOf<String, Any?>("order" to "4711")
val restrictions = mapOf(CommonRestrictions.TENANT_ID to "myTenant")
val cmd = StartProcessByMessageAtElementCmd(
messageName = "Msg_OrderReceived",
elementId = "Activity_ProcessOrder",
payloadSupplier = PayloadSupplier { payload },
restrictions = restrictions
)

assertThat(cmd.messageName).isEqualTo("Msg_OrderReceived")
assertThat(cmd.elementId).isEqualTo("Activity_ProcessOrder")
assertThat(cmd.get()).isEqualTo(payload)
assertThat(cmd.restrictions).isEqualTo(restrictions)
}

@Test
fun `should create command from payload and restrictions`() {
val payload = mapOf<String, Any?>("order" to "4711")
val restrictions = mapOf(CommonRestrictions.TENANT_ID to "myTenant")
val cmd = StartProcessByMessageAtElementCmd("Msg_OrderReceived", "Activity_ProcessOrder", payload, restrictions)

assertThat(cmd.messageName).isEqualTo("Msg_OrderReceived")
assertThat(cmd.elementId).isEqualTo("Activity_ProcessOrder")
assertThat(cmd.get()).isEqualTo(payload)
assertThat(cmd.restrictions).isEqualTo(restrictions)
}

@Test
fun `should create command from payload with empty restrictions`() {
val payload = mapOf<String, Any?>("order" to "4711")
val cmd = StartProcessByMessageAtElementCmd("Msg_OrderReceived", "Activity_ProcessOrder", payload)

assertThat(cmd.messageName).isEqualTo("Msg_OrderReceived")
assertThat(cmd.elementId).isEqualTo("Activity_ProcessOrder")
assertThat(cmd.get()).isEqualTo(payload)
assertThat(cmd.restrictions).isEmpty()
}

@Test
fun `should create command without payload and restrictions`() {
val cmd = StartProcessByMessageAtElementCmd("Msg_OrderReceived", "Activity_ProcessOrder")

assertThat(cmd.messageName).isEqualTo("Msg_OrderReceived")
assertThat(cmd.elementId).isEqualTo("Activity_ProcessOrder")
assertThat(cmd.get()).isEmpty()
assertThat(cmd.restrictions).isEmpty()
}
}
15 changes: 14 additions & 1 deletion docs/process-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ It allows to start new process instances.
It is intended to be used in outbound adapters of the port/adapter architecture
to control the process engine from your application.

There are three ways to start processes:
There are four ways to start processes:
* by providing a process definition key
* by providing a start message
* by providing a process definition key and a specific activity to start at
* by providing a start message and a specific activity to start at

In all cases, you might provide a process payload passed to the started process instance.

Expand Down Expand Up @@ -57,6 +58,18 @@ public class ProcessStarter {
).get();
}

@SneakyThrows
public void startByMessageAtActivity(Order order) {
startProcessApi.startProcess(
new StartProcessByMessageAtElementCmd(
"Msg_OrderReceived",
"Activity_ProcessOrder",
() -> Map.of("order", order),
Map.of()
)
).get();
}

}
```

Expand Down