From 69fa316675b624cf61eaa1d72d8689647f9379aa Mon Sep 17 00:00:00 2001 From: Michael Fritsch Date: Fri, 19 Jan 2024 14:01:16 +0100 Subject: [PATCH] feat(#358): support List> variable factory --- .../kotlin/itest/CamundaBpmDataITestBase.kt | 30 ++++- .../itest/RuntimeServiceAdapterITest.kt | 3 + .../kotlin/itest/TaskServiceAdapterITest.kt | 23 +++- .../kotlin/itest/VariableMapAdapterITest.kt | 43 ++++++- .../kotlin/itest/VariableScopeAdapterITest.kt | 3 +- .../camunda/bpm/data/CamundaBpmData.kt | 15 +++ .../camunda/bpm/data/CamundaBpmDataKotlin.kt | 20 ++- .../list/AbstractListReadWriteAdapter.kt | 6 +- .../AbstractListOfMapsReadWriteAdapter.kt | 62 ++++++++++ ...ListOfMapsReadAdapterLockedExternalTask.kt | 64 ++++++++++ .../ListOfMapsReadWriteAdapterCaseService.kt | 61 +++++++++ ...istOfMapsReadWriteAdapterRuntimeService.kt | 49 ++++++++ .../ListOfMapsReadWriteAdapterTaskService.kt | 48 ++++++++ .../ListOfMapsReadWriteAdapterVariableMap.kt | 47 +++++++ ...ListOfMapsReadWriteAdapterVariableScope.kt | 47 +++++++ .../map/AbstractMapReadWriteAdapter.kt | 6 +- .../set/AbstractSetReadWriteAdapter.kt | 4 +- .../data/factory/ListOfMapsVariableFactory.kt | 116 ++++++++++++++++++ .../ListOfMapsVariableFactoryTest.java | 88 +++++++++++++ 19 files changed, 712 insertions(+), 23 deletions(-) create mode 100644 extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/AbstractListOfMapsReadWriteAdapter.kt create mode 100644 extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadAdapterLockedExternalTask.kt create mode 100644 extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterCaseService.kt create mode 100644 extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterRuntimeService.kt create mode 100644 extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterTaskService.kt create mode 100644 extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterVariableMap.kt create mode 100644 extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterVariableScope.kt create mode 100644 extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/factory/ListOfMapsVariableFactory.kt create mode 100644 extension/core/src/test/java/io/holunda/camunda/bpm/data/factory/ListOfMapsVariableFactoryTest.java diff --git a/example/itest/src/test/kotlin/itest/CamundaBpmDataITestBase.kt b/example/itest/src/test/kotlin/itest/CamundaBpmDataITestBase.kt index 7f5d1696..802436ac 100644 --- a/example/itest/src/test/kotlin/itest/CamundaBpmDataITestBase.kt +++ b/example/itest/src/test/kotlin/itest/CamundaBpmDataITestBase.kt @@ -11,6 +11,7 @@ import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.customVariable import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.dateVariable import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.doubleVariable import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.intVariable +import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.listOfMapsVariable import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.listVariable import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.mapVariable import io.holunda.camunda.bpm.data.CamundaBpmDataKotlin.setVariable @@ -32,6 +33,8 @@ import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Value import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.DOUBLE_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.INT import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.INT_LOCAL +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LIST_MAP_STRING_OBJECT +import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LIST_MAP_STRING_OBJECT_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LIST_STRING import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LIST_STRING_LOCAL import io.holunda.camunda.bpm.data.itest.CamundaBpmDataITestBase.Companion.Values.LONG @@ -88,6 +91,7 @@ abstract class CamundaBpmDataITestBase : SpringScenarioTest> = listVariable("List Of String Variable") val SET_STRING_VAR: VariableFactory> = setVariable("Set Of String Variable") val MAP_STRING_LONG_VAR: VariableFactory> = mapVariable("Map Of String to String Variable") + val LIST_MAP_STRING_OBJECT_VAR: VariableFactory>> = listOfMapsVariable("List Of Maps Of String to Any") val COMPLEX_SET_VAR: VariableFactory> = setVariable("Complex Set") val COMPLEX_LIST_VAR: VariableFactory> = listVariable("Complex List") val COMPLEX_MAP_VAR: VariableFactory> = mapVariable("Complex Map") @@ -107,6 +111,12 @@ abstract class CamundaBpmDataITestBase : SpringScenarioTest factory key type. + * @param factory value type. + * @return variable factory for given type. + */ + @JvmStatic + fun listOfMapsVariable(variableName: String, keyClazz: Class, valueClazz: Class): VariableFactory>> { + return ListOfMapsVariableFactory(variableName, keyClazz, valueClazz) + } + /** * Creates a variable factory for set of custom type. * diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/CamundaBpmDataKotlin.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/CamundaBpmDataKotlin.kt index 091e6e12..880fc00b 100644 --- a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/CamundaBpmDataKotlin.kt +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/CamundaBpmDataKotlin.kt @@ -103,11 +103,28 @@ object CamundaBpmDataKotlin { */ inline fun listVariableNotNull(name: String): VariableFactory> = ListVariableFactory.forType(name) + /** + * Reified version of list of maps variable factory. + * @param name The name of the variable. + * @param K The type of the variable key. + * @param V The type of the variable value. + * @return instance of [VariableFactory] + */ + inline fun listOfMapsVariable(name: String): VariableFactory>> = ListOfMapsVariableFactory.forType(name) + + /** + * Reified version of list of maps variable factory. + * @param name The name of the variable. + * @param K The type of the variable key. + * @param V The type of the variable value. + * @return instance of [VariableFactory] + */ + inline fun listOfMapsVariableNotNull(name: String): VariableFactory>> = ListOfMapsVariableFactory.forType(name) + /** * Reified version of set variable factory. * @param name The name of the variable. * @param T The type of the variable. - * @param wrap a boolean flag controlling if the serializer should wrap a list into a wrapper object. Set this flag to true, if you use complex types as T. * @return instance of [VariableFactory] */ inline fun setVariable(name: String): VariableFactory> = SetVariableFactory.forType(name) @@ -116,7 +133,6 @@ object CamundaBpmDataKotlin { * Reified version of set variable factory. * @param name The name of the variable. * @param T The type of the variable. - * @param wrap a boolean flag controlling if the serializer should wrap a list into a wrapper object. Set this flag to true, if you use complex types as T. * @return instance of [VariableFactory] */ inline fun setVariableNotNull(name: String): VariableFactory> = SetVariableFactory.forType(name) diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.kt index 697c58d9..c5b11c93 100644 --- a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.kt +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/list/AbstractListReadWriteAdapter.kt @@ -33,7 +33,9 @@ abstract class AbstractListReadWriteAdapter(variableName: String, protected v @Suppress("UNCHECKED_CAST") valueAsList as List } else { - throw WrongVariableTypeException("Error reading " + variableName + ": Wrong list type detected, expected " + memberClazz.name + ", but was not found in " + valueAsList) + throw WrongVariableTypeException( + "Error reading $variableName: Wrong list type detected, expected ${memberClazz.name}, but was not found in $valueAsList" + ) } } } @@ -41,6 +43,6 @@ abstract class AbstractListReadWriteAdapter(variableName: String, protected v } override fun getTypedValue(value: Any?, isTransient: Boolean): TypedValue { - return getTypedValue>(MutableList::class.java, value, isTransient) + return getTypedValue(MutableList::class.java, value, isTransient) } } diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/AbstractListOfMapsReadWriteAdapter.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/AbstractListOfMapsReadWriteAdapter.kt new file mode 100644 index 00000000..6a4498b2 --- /dev/null +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/AbstractListOfMapsReadWriteAdapter.kt @@ -0,0 +1,62 @@ +package io.holunda.camunda.bpm.data.adapter.listofmaps + +import io.holunda.camunda.bpm.data.adapter.AbstractReadWriteAdapter +import io.holunda.camunda.bpm.data.adapter.ValueWrapperUtil.getTypedValue +import io.holunda.camunda.bpm.data.adapter.WrongVariableTypeException +import org.camunda.bpm.engine.variable.value.TypedValue + +/** + * Base class for all list of maps read-write adapter. + * + * @param [K] key type. + * @param [V] value type. + * @param variableName name of variable. + * @param keyClazz key class. + * @param valueClazz value class. + */ +abstract class AbstractListOfMapsReadWriteAdapter( + variableName: String, + protected val keyClazz: Class, + protected val valueClazz: Class +) : AbstractReadWriteAdapter>>(variableName) { + /** + * Read the value of null. + * + * @param value raw value. + * @return list or null. + */ + protected fun getOrNull(value: Any?): List>? { + if (value == null) { + return null + } + if (MutableList::class.java.isAssignableFrom(value.javaClass)) { + val valueAsList = value as List<*> + return if (valueAsList.isEmpty()) { + emptyList() + } else { + val valueAsMap = valueAsList.iterator().next() as Map<*, *> + if (MutableMap::class.java.isAssignableFrom(valueAsMap.javaClass)) { + val (key, value1) = valueAsMap.entries.iterator().next() + if (keyClazz.isAssignableFrom(key!!.javaClass) && + valueClazz.isAssignableFrom(value1!!.javaClass)) { + @Suppress("UNCHECKED_CAST") + valueAsList as List> + } else { + throw WrongVariableTypeException( + "Error reading $variableName: Wrong map type detected, expected Map<${keyClazz.name},${valueClazz.name}, but was not found in $valueAsMap" + ) + } + } else { + throw WrongVariableTypeException( + "Error reading $variableName: Wrong list type detected, expected List, but was not found in $valueAsList") + } + } + } + throw WrongVariableTypeException( + "Error reading $variableName: Couldn't read value of type List of Maps from $value") + } + + override fun getTypedValue(value: Any?, isTransient: Boolean): TypedValue { + return getTypedValue(MutableList::class.java, value, isTransient) + } +} diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadAdapterLockedExternalTask.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadAdapterLockedExternalTask.kt new file mode 100644 index 00000000..2dbc3c1e --- /dev/null +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadAdapterLockedExternalTask.kt @@ -0,0 +1,64 @@ +package io.holunda.camunda.bpm.data.adapter.listofmaps + +import org.camunda.bpm.engine.externaltask.LockedExternalTask +import org.camunda.bpm.engine.variable.Variables +import java.util.* +import kotlin.collections.Map + +/** + * Read adapter for external task. + * + * @param [K] key type. + * @param [V] value type. + */ +class ListOfMapsReadAdapterLockedExternalTask( + private val lockedExternalTask: LockedExternalTask, + variableName: String, + keyClazz: Class, + valueClazz: Class +) : AbstractListOfMapsReadWriteAdapter(variableName, keyClazz, valueClazz) { + + private val value: Any? + get() = Optional.ofNullable(lockedExternalTask.variables) + .orElse(Variables.createVariables())[variableName] + + override fun getOptional(): Optional>> { + return Optional.ofNullable( + getOrNull( + value + ) + ) + } + + override fun set(value: List>, isTransient: Boolean) { + throw UnsupportedOperationException("Can't set a variable on an external task") + } + + override fun setLocal(value: List>, isTransient: Boolean) { + throw UnsupportedOperationException("Can't set a local variable on an external task") + } + + override fun getLocal(): List> { + throw UnsupportedOperationException("Can't get a local variable on an external task") + } + + override fun getLocalOptional(): Optional>> { + throw UnsupportedOperationException("Can't get a local variable on an external task") + } + + override fun getLocalOrDefault(defaultValue: List>): List> { + throw UnsupportedOperationException("Can't get a local variable on an external task") + } + + override fun getLocalOrNull(): List> { + throw UnsupportedOperationException("Can't get a local variable on an external task") + } + + override fun remove() { + throw UnsupportedOperationException("Can't remove a variable on an external task") + } + + override fun removeLocal() { + throw UnsupportedOperationException("Can't remove a local variable on an external task") + } +} diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterCaseService.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterCaseService.kt new file mode 100644 index 00000000..01a8e663 --- /dev/null +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterCaseService.kt @@ -0,0 +1,61 @@ +package io.holunda.camunda.bpm.data.adapter.listofmaps + +import io.holunda.camunda.bpm.data.adapter.ValueWrapperUtil.getTypedValue +import org.camunda.bpm.engine.CaseService +import java.util.* + +/** + * Read write adapter for case service access. + * + * @param [K] key type. + * @param [V] value type. + * @param caseService case service to use. + * @param caseExecutionId id of the execution to read from and write to. + * @param variableName name of the variable. + * @param keyClazz key class. + * @param valueClazz value class. + */ +class ListOfMapsReadWriteAdapterCaseService( + private val caseService: CaseService, + private val caseExecutionId: String, + variableName: String, + keyClazz: Class, + valueClazz: Class +) : AbstractListOfMapsReadWriteAdapter(variableName, keyClazz, valueClazz) { + + override fun getOptional(): Optional>> { + return Optional.ofNullable( + getOrNull( + caseService.getVariable( + caseExecutionId, variableName + ) + ) + ) + } + + override fun set(value: List>, isTransient: Boolean) { + caseService.setVariable(caseExecutionId, variableName, getTypedValue(value, isTransient)) + } + + override fun getLocalOptional(): Optional>> { + return Optional.ofNullable( + getOrNull( + caseService.getVariableLocal( + caseExecutionId, variableName + ) + ) + ) + } + + override fun setLocal(value: List>, isTransient: Boolean) { + caseService.setVariableLocal(caseExecutionId, variableName, getTypedValue(value, isTransient)) + } + + override fun remove() { + caseService.removeVariable(caseExecutionId, variableName) + } + + override fun removeLocal() { + caseService.removeVariableLocal(caseExecutionId, variableName) + } +} diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterRuntimeService.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterRuntimeService.kt new file mode 100644 index 00000000..d13980b2 --- /dev/null +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterRuntimeService.kt @@ -0,0 +1,49 @@ +package io.holunda.camunda.bpm.data.adapter.listofmaps + +import java.util.* +import org.camunda.bpm.engine.RuntimeService + +/** + * Read write adapter for runtime service access. + * + * @param [K] key type. + * @param [V] value type. + * @param runtimeService runtime service to use. + * @param executionId id of the execution to read from and write to. + * @param variableName name of the variable. + * @param keyClazz key class. + * @param valueClazz value class. + */ +class ListOfMapsReadWriteAdapterRuntimeService( + private val runtimeService: RuntimeService, + private val executionId: String, + variableName: String, + keyClazz: Class, + valueClazz: Class +) : AbstractListOfMapsReadWriteAdapter(variableName, keyClazz, valueClazz) { + + override fun getOptional(): Optional>> { + return Optional.ofNullable(getOrNull(runtimeService.getVariable(executionId, variableName))) + } + + override fun set(value: List>, isTransient: Boolean) { + runtimeService.setVariable(executionId, variableName, getTypedValue(value, isTransient)) + } + + override fun getLocalOptional(): Optional>> { + return Optional.ofNullable( + getOrNull(runtimeService.getVariableLocal(executionId, variableName))) + } + + override fun setLocal(value: List>, isTransient: Boolean) { + runtimeService.setVariableLocal(executionId, variableName, getTypedValue(value, isTransient)) + } + + override fun remove() { + runtimeService.removeVariable(executionId, variableName) + } + + override fun removeLocal() { + runtimeService.removeVariableLocal(executionId, variableName) + } +} diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterTaskService.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterTaskService.kt new file mode 100644 index 00000000..664f5106 --- /dev/null +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterTaskService.kt @@ -0,0 +1,48 @@ +package io.holunda.camunda.bpm.data.adapter.listofmaps + +import org.camunda.bpm.engine.TaskService +import java.util.* + +/** + * Read write adapter for task service access. + * + * @param [K] key type. + * @param [V] value type. + * @param taskService task service to use. + * @param taskId id of the task to read from and write to. + * @param variableName name of the variable. + * @param keyClazz key class. + * @param valueClazz value class. + */ +class ListOfMapsReadWriteAdapterTaskService( + private val taskService: TaskService, + private val taskId: String, + variableName: String, + keyClazz: Class, + valueClazz: Class +) : AbstractListOfMapsReadWriteAdapter(variableName, keyClazz, valueClazz) { + + override fun getOptional(): Optional>> { + return Optional.ofNullable(getOrNull(taskService.getVariable(taskId, variableName))) + } + + override fun set(value: List>, isTransient: Boolean) { + taskService.setVariable(taskId, variableName, getTypedValue(value, isTransient)) + } + + override fun getLocalOptional(): Optional>> { + return Optional.ofNullable(getOrNull(taskService.getVariableLocal(taskId, variableName))) + } + + override fun setLocal(value: List>, isTransient: Boolean) { + taskService.setVariableLocal(taskId, variableName, getTypedValue(value, isTransient)) + } + + override fun remove() { + taskService.removeVariable(taskId, variableName) + } + + override fun removeLocal() { + taskService.removeVariableLocal(taskId, variableName) + } +} diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterVariableMap.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterVariableMap.kt new file mode 100644 index 00000000..3b193259 --- /dev/null +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterVariableMap.kt @@ -0,0 +1,47 @@ +package io.holunda.camunda.bpm.data.adapter.listofmaps + +import io.holunda.camunda.bpm.data.adapter.ValueWrapperUtil.getTypedValue +import org.camunda.bpm.engine.variable.VariableMap +import java.util.* + +/** + * Read-write adapter for variable map. + * + * @param [K] key type. + * @param [V] value type. + * @param variableMap variable map to access. + * @param variableName variable to access. + * @param keyClazz key class. + * @param valueClazz value class. + */ +class ListOfMapsReadWriteAdapterVariableMap( + private val variableMap: VariableMap, + variableName: String, + keyClazz: Class, + valueClazz: Class +) : AbstractListOfMapsReadWriteAdapter(variableName, keyClazz, valueClazz) { + + override fun getOptional(): Optional>> { + return Optional.ofNullable(getOrNull(variableMap[variableName])) + } + + override fun set(value: List>, isTransient: Boolean) { + variableMap.putValueTyped(variableName, getTypedValue(value, isTransient)) + } + + override fun getLocalOptional(): Optional>> { + throw UnsupportedOperationException("Can't get a local variable on a variable map") + } + + override fun setLocal(value: List>, isTransient: Boolean) { + throw UnsupportedOperationException("Can't set a local variable on a variable map") + } + + override fun remove() { + variableMap.remove(variableName) + } + + override fun removeLocal() { + throw UnsupportedOperationException("Can't set a local variable on a variable map") + } +} diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterVariableScope.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterVariableScope.kt new file mode 100644 index 00000000..cdea3664 --- /dev/null +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/listofmaps/ListOfMapsReadWriteAdapterVariableScope.kt @@ -0,0 +1,47 @@ +package io.holunda.camunda.bpm.data.adapter.listofmaps + +import io.holunda.camunda.bpm.data.adapter.ValueWrapperUtil.getTypedValue +import org.camunda.bpm.engine.delegate.VariableScope +import java.util.* + +/** + * Read-write adapter for variable scope. + * + * @param [K] key type. + * @param [V] value type. + * @param variableScope variable scope to access. + * @param variableName variable to access. + * @param keyClazz key class. + * @param valueClazz value class. + */ +class ListOfMapsReadWriteAdapterVariableScope( + private val variableScope: VariableScope, + variableName: String, + keyClazz: Class, + valueClazz: Class +) : AbstractListOfMapsReadWriteAdapter(variableName, keyClazz, valueClazz) { + + override fun getOptional(): Optional>> { + return Optional.ofNullable(getOrNull(variableScope.getVariable(variableName))) + } + + override fun set(value: List>, isTransient: Boolean) { + variableScope.setVariable(variableName, getTypedValue(value, isTransient)) + } + + override fun getLocalOptional(): Optional>> { + return Optional.ofNullable(getOrNull(variableScope.getVariableLocal(variableName))) + } + + override fun setLocal(value: List>, isTransient: Boolean) { + variableScope.setVariableLocal(variableName, getTypedValue(value, isTransient)) + } + + override fun remove() { + variableScope.removeVariable(variableName) + } + + override fun removeLocal() { + variableScope.removeVariableLocal(variableName) + } +} diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.kt index d2b1c498..b0792e6c 100644 --- a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.kt +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/map/AbstractMapReadWriteAdapter.kt @@ -40,9 +40,7 @@ abstract class AbstractMapReadWriteAdapter( valueAsMap as Map } else { throw WrongVariableTypeException( - "Error reading " + variableName + ": Wrong map type detected, expected Map<" - + keyClazz.name + "," + valueClazz.name - + ", but was not found in " + valueAsMap + "Error reading $variableName: Wrong map type detected, expected Map<${keyClazz.name},${valueClazz.name}, but was not found in $valueAsMap" ) } } @@ -51,6 +49,6 @@ abstract class AbstractMapReadWriteAdapter( } override fun getTypedValue(value: Any?, isTransient: Boolean): TypedValue { - return getTypedValue>(MutableMap::class.java, value, isTransient) + return getTypedValue(MutableMap::class.java, value, isTransient) } } diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.kt index bdbfb7c9..a800498f 100644 --- a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.kt +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/adapter/set/AbstractSetReadWriteAdapter.kt @@ -32,7 +32,7 @@ abstract class AbstractSetReadWriteAdapter(variableName: String, protected va @Suppress("UNCHECKED_CAST") valueAsList as Set } else { - throw WrongVariableTypeException("Error reading " + variableName + ": Wrong set type detected, expected " + memberClazz.name + ", but was not found in " + valueAsList) + throw WrongVariableTypeException("Error reading $variableName: Wrong set type detected, expected ${memberClazz.name}, but was not found in $valueAsList") } } } @@ -40,6 +40,6 @@ abstract class AbstractSetReadWriteAdapter(variableName: String, protected va } override fun getTypedValue(value: Any?, isTransient: Boolean): TypedValue { - return getTypedValue>(MutableSet::class.java, value, isTransient) + return getTypedValue(MutableSet::class.java, value, isTransient) } } diff --git a/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/factory/ListOfMapsVariableFactory.kt b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/factory/ListOfMapsVariableFactory.kt new file mode 100644 index 00000000..afbe3e7d --- /dev/null +++ b/extension/core/src/main/kotlin/io/holunda/camunda/bpm/data/factory/ListOfMapsVariableFactory.kt @@ -0,0 +1,116 @@ +package io.holunda.camunda.bpm.data.factory + +import io.holunda.camunda.bpm.data.adapter.ReadAdapter +import io.holunda.camunda.bpm.data.adapter.WriteAdapter +import io.holunda.camunda.bpm.data.adapter.listofmaps.* +import java.util.* +import org.camunda.bpm.engine.CaseService +import org.camunda.bpm.engine.RuntimeService +import org.camunda.bpm.engine.TaskService +import org.camunda.bpm.engine.delegate.VariableScope +import org.camunda.bpm.engine.externaltask.LockedExternalTask +import org.camunda.bpm.engine.variable.VariableMap + +/** + * Variable factory of a base parametrized list of maps type. + * + * @param [K]> member key type of the factory. + * @param [V] member value type of the factory. + */ +class ListOfMapsVariableFactory( + override val name: String, + val keyClass: Class, + val valueClass: Class +) : VariableFactory>> { + + companion object { + /** + * static factory method for creating an instance + */ + inline fun forType(name: String) = + ListOfMapsVariableFactory(name, K::class.java, V::class.java) + } + + override fun on(variableScope: VariableScope): WriteAdapter>> { + return ListOfMapsReadWriteAdapterVariableScope(variableScope, name, keyClass, valueClass) + } + + override fun from(variableScope: VariableScope): ReadAdapter>> { + return ListOfMapsReadWriteAdapterVariableScope(variableScope, name, keyClass, valueClass) + } + + override fun on(variableMap: VariableMap): WriteAdapter>> { + return ListOfMapsReadWriteAdapterVariableMap(variableMap, name, keyClass, valueClass) + } + + override fun from(variableMap: VariableMap): ReadAdapter>> { + return ListOfMapsReadWriteAdapterVariableMap(variableMap, name, keyClass, valueClass) + } + + override fun on( + runtimeService: RuntimeService, + executionId: String + ): WriteAdapter>> { + return ListOfMapsReadWriteAdapterRuntimeService( + runtimeService, executionId, name, keyClass, valueClass) + } + + override fun from( + runtimeService: RuntimeService, + executionId: String + ): ReadAdapter>> { + return ListOfMapsReadWriteAdapterRuntimeService( + runtimeService, executionId, name, keyClass, valueClass) + } + + override fun on(taskService: TaskService, taskId: String): WriteAdapter>> { + return ListOfMapsReadWriteAdapterTaskService(taskService, taskId, name, keyClass, valueClass) + } + + override fun from(taskService: TaskService, taskId: String): ReadAdapter>> { + return ListOfMapsReadWriteAdapterTaskService(taskService, taskId, name, keyClass, valueClass) + } + + override fun on( + caseService: CaseService, + caseExecutionId: String + ): WriteAdapter>> { + return ListOfMapsReadWriteAdapterCaseService( + caseService, caseExecutionId, name, keyClass, valueClass) + } + + override fun from( + caseService: CaseService, + caseExecutionId: String + ): ReadAdapter>> { + return ListOfMapsReadWriteAdapterCaseService( + caseService, caseExecutionId, name, keyClass, valueClass) + } + + override fun from(lockedExternalTask: LockedExternalTask): ReadAdapter>> { + return ListOfMapsReadAdapterLockedExternalTask(lockedExternalTask, name, keyClass, valueClass) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || javaClass != other.javaClass) return false + val that = other as ListOfMapsVariableFactory<*, *> + return name == that.name && keyClass == that.keyClass && valueClass == that.valueClass + } + + override fun hashCode(): Int { + return Objects.hash(name, keyClass, valueClass) + } + + override fun toString(): String { + return "ListOfMapsVariableFactory{" + + "name='" + + name + + '\'' + + ", keyClazz=" + + keyClass + + ", valueClazz=" + + valueClass + + '}' + } +} diff --git a/extension/core/src/test/java/io/holunda/camunda/bpm/data/factory/ListOfMapsVariableFactoryTest.java b/extension/core/src/test/java/io/holunda/camunda/bpm/data/factory/ListOfMapsVariableFactoryTest.java new file mode 100644 index 00000000..e2a12c2a --- /dev/null +++ b/extension/core/src/test/java/io/holunda/camunda/bpm/data/factory/ListOfMapsVariableFactoryTest.java @@ -0,0 +1,88 @@ +package io.holunda.camunda.bpm.data.factory; + +import io.holunda.camunda.bpm.data.CamundaBpmData; +import io.holunda.camunda.bpm.data.adapter.listofmaps.ListOfMapsReadWriteAdapterCaseService; +import io.holunda.camunda.bpm.data.adapter.listofmaps.ListOfMapsReadWriteAdapterRuntimeService; +import io.holunda.camunda.bpm.data.adapter.listofmaps.ListOfMapsReadWriteAdapterTaskService; +import io.holunda.camunda.bpm.data.adapter.listofmaps.ListOfMapsReadWriteAdapterVariableMap; +import io.holunda.camunda.bpm.data.adapter.listofmaps.ListOfMapsReadWriteAdapterVariableScope; +import org.camunda.bpm.engine.CaseService; +import org.camunda.bpm.engine.RuntimeService; +import org.camunda.bpm.engine.TaskService; +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.engine.variable.VariableMap; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +class ListOfMapsVariableFactoryTest { + + private final ListOfMapsVariableFactory variableFactory = new ListOfMapsVariableFactory<>("string", String.class, Object.class); + + @Test + void shouldHaveNameAndVariableClass() { + assertThat(variableFactory.getName()).isEqualTo("string"); + assertThat(variableFactory.getKeyClass()).isEqualTo(String.class); + assertThat(variableFactory.getValueClass()).isEqualTo(Object.class); + } + + @Test + void shouldHaveCorrectHashCodeAndEquals() { + VariableFactory>> foo = CamundaBpmData.listOfMapsVariable("foo", String.class, Object.class); + + assertThat(variableFactory).isEqualTo(variableFactory); + assertThat(variableFactory.hashCode()).isEqualTo(variableFactory.hashCode()); + + + assertThat(variableFactory).isNotEqualTo(foo); + assertThat(variableFactory.hashCode()).isNotEqualTo(foo.hashCode()); + } + + @Test + void shouldReturnAdapterForDelegateExecution() { + DelegateExecution delegateExecution = mock(DelegateExecution.class); + + assertThat(variableFactory.on(delegateExecution)).isInstanceOf(ListOfMapsReadWriteAdapterVariableScope.class); + assertThat(variableFactory.from(delegateExecution)).isInstanceOf(ListOfMapsReadWriteAdapterVariableScope.class); + } + + @Test + void shouldReturnAdapterForVariableMap() { + VariableMap variableMap = mock(VariableMap.class); + + assertThat(variableFactory.on(variableMap)).isInstanceOf(ListOfMapsReadWriteAdapterVariableMap.class); + assertThat(variableFactory.from(variableMap)).isInstanceOf(ListOfMapsReadWriteAdapterVariableMap.class); + } + + @Test + void shouldReturnAdapterForRuntimeService() { + RuntimeService runtimeService = mock(RuntimeService.class); + String executionId = UUID.randomUUID().toString(); + + assertThat(variableFactory.on(runtimeService, executionId)).isInstanceOf(ListOfMapsReadWriteAdapterRuntimeService.class); + assertThat(variableFactory.from(runtimeService, executionId)).isInstanceOf(ListOfMapsReadWriteAdapterRuntimeService.class); + } + + @Test + void shouldReturnAdapterForTaskService() { + TaskService taskService = mock(TaskService.class); + String taskId = UUID.randomUUID().toString(); + + assertThat(variableFactory.on(taskService, taskId)).isInstanceOf(ListOfMapsReadWriteAdapterTaskService.class); + assertThat(variableFactory.from(taskService, taskId)).isInstanceOf(ListOfMapsReadWriteAdapterTaskService.class); + } + + @Test + void shouldReturnAdapterForCaseService() { + CaseService caseService = mock(CaseService.class); + String caseExecutionId = UUID.randomUUID().toString(); + + assertThat(variableFactory.on(caseService, caseExecutionId)).isInstanceOf(ListOfMapsReadWriteAdapterCaseService.class); + assertThat(variableFactory.from(caseService, caseExecutionId)).isInstanceOf(ListOfMapsReadWriteAdapterCaseService.class); + } +}