Usage in Kotlin
The following snippets demonstrate the usage of the library from Kotlin
Define variable#
import io.holunda.data.CamundaBpmDataKotlin
object Variables {
val ORDER_ID = stringVariable("orderId")
val ORDER: VariableFactory<Order> = customVariable("order")
val ORDER_APPROVED = booleanVariable("orderApproved")
val ORDER_POSITION: VariableFactory<OrderPosition> = customVariable("orderPosition")
val ORDER_TOTAL: VariableFactory<BigDecimal> = customVariable("orderTotal")
}
Define nonNull variable#
IMPORTANT: Since 1.5.0 all predefined variable types are nullable by default. (For more information, see here: Github Issue) If you want to define a variable to be non-null-able, please call nonNull on variable factory as shown in the example below.
import io.holunda.data.CamundaBpmDataKotlin
object Variables {
val ORDER_ID: VariableFactory<String> = stringVariable("orderId").nonNull
val CUSTOMER_ID: VariableFactory<String?> = stringVariable("orderId")
}
#
Read variable from Java delegate#
@Configuration
class JavaDelegates {
@Bean
fun calculateOrderPositions() = JavaDelegate { execution ->
val orderPosition = ORDER_POSITION.from(execution).get()
// order position is of type OrderPosition
}
}
Write variable from Java delegate#
import java.math.BigDecimal
@Configuration
class JavaDelegates {
@Bean
fun calculateOrderPositions() = JavaDelegate { execution ->
val orderPosition = ORDER_POSITION.from(execution).get()
ORDER_TOTAL.on(execution).set {
orderPosition.netCost.times(BigDecimal.valueOf(orderPosition.amount))
}
}
}
Remove variable from Java delegate#
@Configuration
class JavaDelegates {
@Bean
fun removeTotal() = JavaDelegate { execution ->
ORDER_TOTAL.on(execution).remove()
}
}
Update variable from Java delegate#
import java.math.BigDecimal
@Configuration
class JavaDelegates {
@Bean
fun calculateOrderPositions() = JavaDelegate { execution ->
val orderPosition = ORDER_POSITION.from(execution).get()
ORDER_TOTAL.on(execution).update {
it.plus(orderPosition.netCost.times(BigDecimal.valueOf(orderPosition.amount)))
}
}
}
Fluent API to remove several variables#
import io.holunda.camunda.bpm.data.remove
@Configuration
class JavaDelegates {
@Bean
fun removeProcessVariables() = JavaDelegate { execution ->
execution
.remove(ORDER_ID)
.remove(ORDER)
.remove(ORDER_APPROVED)
.remove(ORDER_TOTAL)
.removeLocal(ORDER_POSITIONS)
}
}
Fluent API to set several variables#
@Component
class SomeService(
private val runtimeService: RuntimeService,
private val taskService: TaskService
) {
fun setNewValuesForExecution(executionId: String, rderId: String, orderApproved: Boolean) {
runtimeService.writer(executionId)
.set(ORDER_ID, orderId)
.set(ORDER_APPROVED, orderApproved)
.update(ORDER_TOTAL, { amount -> amount.add(10) })
}
fun setNewValuesForTask(taskId: String, orderId: String, orderApproved: Boolean) {
taskService.writer(taskId)
.set(ORDER_ID, orderId)
.set(ORDER_APPROVED, orderApproved)
}
fun start() {
val variables = createProcessVariables()
.set(ORDER_ID, "4711")
.set(ORDER_APPROVED, false)
runtimeService.startProcessInstanceById("myId", "businessKey", variables)
}
}
Fluent API to read several variables#
@Component
class SomeService(
private val runtimeService: RuntimeService,
private val taskService: TaskService
) {
fun readValuesFromExecution(executionId: String): String {
val reader = CamundaBpmData.reader(runtimeService, executionId)
val orderId = reader.get(ORDER_ID)
val orderApproved = reader.get(ORDER_APPROVED)
if (orderApproved) {
// ...
}
return orderId
}
fun readValuesFromTask(taskId: String ): String {
val reader = CamundaBpmData.reader(taskService, taskId)
val orderId = reader.get(ORDER_ID)
val orderApproved = reader.get(ORDER_APPROVED)
if (orderApproved) {
// ...
}
return orderId
}
}
Anti-Corruption-Layer: Wrap variables to correlate#
@Component
class SomeService {
val MESSAGE_ACL = CamundaBpmDataMapper.identityReplace("__transient", true);
fun correlate() {
val variables = CamundaBpmData.builder()
.set(ORDER_ID, "4711")
.set(ORDER_APPROVED, false)
.build();
runtimeService.correlateMessage("message_1", MESSAGE_ACL.wrap(variables));
}
}
Anti-Corruption-Layer: Check and wrap variables to correlate#
@Component
class SomeService {
val MY_ACL = CamundaBpmDataACL.guardTransformingReplace(
"__transient",
true,
VariablesGuard(exists(ORDER_ID)),
IdentityVariableMapTransformer
);
fun correlate() {
val variables = CamundaBpmData.builder()
.set(ORDER_ID, "4711")
.set(ORDER_APPROVED, false)
.build();
runtimeService.correlateMessage("message_1", MESSAGE_ACL.checkAndWrap(variables));
}
}
Define Guards to validate variables in the process#
@Configuration
class VariableGuardConfiguration {
companion object {
const val LOAD_OPERATIONAL_FILE_GUARD = "loadOperationalFileGuard";
}
@Bean
// assuming dependencys to implement javax.validation:validation-api are present
fun validatorSupplier(): Supplier<Validator> = Supplier {
Validation.buildDefaultValidatorFactory().validator
}
@Bean(LOAD_OPERATIONAL_FILE_GUARD)
fun loadOperationalFileGuard(validatorSupplier : Supplier<Validator>): ExecutionListener =
DefaultGuardExecutionListener(
VariablesGuard(
listOf(
REQUIRED_VALUE.exists(),
FUTURE_VALUE.notExists(),
THE_ANSWER.hasValue(42),
MY_DIRECTION.hasOneOfValues(setOf("left", "up", "down")),
USER_EMAIL.isEmail(),
DOCUMENT_ID.isUuid(),
DOCUMENT_BODY.matches { return@matches true },
DOCUMENT_BODY.matches(this::validationMessageSupplier) { return@matches true },
DOCUMENT_BODY.matchesRegexLocal(Regex("^Dude.*"), "Starts with 'Dude'"),
MY_DOCUMENT.isValidBean(validatorSupplier)
)
), true
)
private fun validationMessageSupplier(variableFactory: VariableFactory<String>, localLabel: String, option: Optional<String>) =
"Expecting$localLabel variable '${variableFactory.name}' to always match my document body matcher, but its value '${option.get()}' has not."
}
class MyDocument(@field:Email val email: String)
Example project#
For more examples, please check out the Kotlin Example project, at GitHub.