Skip to content

Commit 08ee7c2

Browse files
authored
Merge pull request #160 from bpm-crafters/feat/151-variable_converter
Allow to specify a converter per variable as an annotation attribute
2 parents ed652cc + d1c96fc commit 08ee7c2

File tree

16 files changed

+364
-215
lines changed

16 files changed

+364
-215
lines changed

spring-boot-starter/src/main/kotlin/dev/bpmcrafters/processengine/worker/ProcessEngineWorker.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package dev.bpmcrafters.processengine.worker
22

3-
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.DEFAULT_VALUE
43
import org.springframework.core.annotation.AliasFor
54

65
/**
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
package dev.bpmcrafters.processengine.worker
22

3-
class RejectJobException {
4-
}
3+
/**
4+
* Special exception indicating the task rejection.
5+
*/
6+
class RejectJobException(
7+
/**
8+
* Reason for rejection.
9+
*/
10+
override val message: String
11+
) : Exception()
Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package dev.bpmcrafters.processengine.worker
22

3+
import dev.bpmcrafters.processengine.worker.registrar.VariableConverter
34
import org.springframework.core.annotation.AliasFor
5+
import kotlin.reflect.KClass
46

57
/**
68
* Indicates a typed process variable to be injected into the worker method.
@@ -9,25 +11,37 @@ import org.springframework.core.annotation.AliasFor
911
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.ANNOTATION_CLASS)
1012
@MustBeDocumented
1113
annotation class Variable(
14+
/**
15+
* Name of the variable.
16+
*/
17+
@get:AliasFor(attribute = "value")
18+
val name: String = DEFAULT_UNNAMED_NAME,
19+
/**
20+
* Name of the variable.
21+
*/
22+
@get:AliasFor(attribute = "name")
23+
val value: String = DEFAULT_UNNAMED_NAME,
24+
/**
25+
* Indicates that a variable is mandatory. Defaults to `true`.
26+
*/
27+
val mandatory: Boolean = true,
28+
/**
29+
* Specifies a converter class for this variable.
30+
*/
31+
val converter: KClass<out VariableConverter> = DefaultVariableConverter::class,
32+
) {
33+
/**
34+
* Null object for converter, serves as a marker to use a globally defined converter.
35+
* @since 0.5.1
36+
*/
37+
object DefaultVariableConverter : VariableConverter {
38+
override fun <T : Any> mapToType(value: Any?, type: Class<T>): T = throw NotImplementedError()
39+
}
40+
41+
companion object {
1242
/**
13-
* Name of the variable.
14-
*/
15-
@get:AliasFor(attribute = "value")
16-
val name: String = DEFAULT_UNNAMED_NAME,
17-
/**
18-
* Name of the variable.
19-
*/
20-
@get:AliasFor(attribute = "name")
21-
val value: String = DEFAULT_UNNAMED_NAME,
22-
/**
23-
* Indicates that a variable is mandatory. Defaults to `true`.
43+
* Null value for the variable name.
2444
*/
25-
val mandatory: Boolean = true
26-
) {
27-
companion object {
28-
/**
29-
* Null value for the variable name.
30-
*/
31-
const val DEFAULT_UNNAMED_NAME = "__unnamed"
32-
}
45+
const val DEFAULT_UNNAMED_NAME = "__unnamed"
46+
}
3347
}

spring-boot-starter/src/main/kotlin/dev/bpmcrafters/processengine/worker/configuration/ProcessEngineWorkerAutoConfiguration.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
package dev.bpmcrafters.processengine.worker.configuration
22

33
import com.fasterxml.jackson.databind.ObjectMapper
4-
import dev.bpmcrafters.processengine.worker.registrar.VariableConverter
4+
import dev.bpmcrafters.processengine.worker.registrar.JacksonVariableConverter
55
import dev.bpmcrafters.processengine.worker.registrar.ParameterResolver
66
import dev.bpmcrafters.processengine.worker.registrar.ResultResolver
7-
import org.springframework.beans.factory.annotation.Qualifier
7+
import dev.bpmcrafters.processengine.worker.registrar.VariableConverter
88
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
99
import org.springframework.boot.context.properties.EnableConfigurationProperties
1010
import org.springframework.context.annotation.Bean
1111
import org.springframework.context.annotation.Configuration
12-
import java.util.concurrent.ExecutorService
13-
import java.util.concurrent.Executors
1412

1513
/**
1614
* Auto configuration.
15+
* @since 0.5.0
1716
*/
1817
@Configuration
1918
@EnableConfigurationProperties(ProcessEngineWorkerProperties::class)
@@ -24,7 +23,8 @@ class ProcessEngineWorkerAutoConfiguration {
2423
*/
2524
@Bean
2625
@ConditionalOnMissingBean
27-
fun defaultVariableConverter(objectMapper: ObjectMapper): VariableConverter = VariableConverter(objectMapper = objectMapper)
26+
fun defaultJacksonVariableConverter(objectMapper: ObjectMapper): VariableConverter
27+
= JacksonVariableConverter(objectMapper = objectMapper)
2828

2929
/**
3030
* Initializes parameter resolver.

spring-boot-starter/src/main/kotlin/dev/bpmcrafters/processengine/worker/configuration/ProcessEngineWorkerDeploymentAutoConfiguration.kt

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,38 @@ import org.springframework.core.io.support.ResourcePatternResolver
1212

1313
/**
1414
* Auto-configuration for auto-deployment.
15+
* 0.5.0
1516
*/
1617
@AutoConfiguration
1718
@EnableConfigurationProperties(ProcessEngineWorkerDeploymentProperties::class)
1819
class ProcessEngineWorkerDeploymentAutoConfiguration {
1920

20-
/**
21-
* Create a process deployment bean, independent of the auto-deployment feature.
22-
*/
23-
@Bean
24-
@ConditionalOnMissingBean
25-
fun processDeployment(
26-
resourcePatternResolver: ResourcePatternResolver,
27-
deploymentApi: DeploymentApi,
28-
processEngineWorkerDeploymentProperties: ProcessEngineWorkerDeploymentProperties
29-
) = ProcessDeployment(
30-
resourcePatternResolver = resourcePatternResolver,
31-
deploymentApi = deploymentApi,
32-
processEngineWorkerDeploymentProperties = processEngineWorkerDeploymentProperties
33-
)
21+
/**
22+
* Create a process deployment bean, independent of the auto-deployment feature.
23+
*/
24+
@Bean
25+
@ConditionalOnMissingBean
26+
fun processDeployment(
27+
resourcePatternResolver: ResourcePatternResolver,
28+
deploymentApi: DeploymentApi,
29+
processEngineWorkerDeploymentProperties: ProcessEngineWorkerDeploymentProperties
30+
) = ProcessDeployment(
31+
resourcePatternResolver = resourcePatternResolver,
32+
deploymentApi = deploymentApi,
33+
processEngineWorkerDeploymentProperties = processEngineWorkerDeploymentProperties
34+
)
3435

35-
/**
36-
* Configures a trigger for auto-deployment triggered by application start event.
37-
*/
38-
@ConditionalOnProperty(
39-
prefix = ProcessEngineWorkerDeploymentProperties.PREFIX,
40-
name = ["enabled"],
41-
havingValue = "true",
42-
matchIfMissing = false
43-
)
44-
@Bean
45-
fun autoDeploymentOnStartup(processDeployment: ProcessDeployment) =
46-
AutoDeploymentOnStartup(processDeployment = processDeployment)
36+
/**
37+
* Configures a trigger for auto-deployment triggered by application start event.
38+
*/
39+
@ConditionalOnProperty(
40+
prefix = ProcessEngineWorkerDeploymentProperties.PREFIX,
41+
name = ["enabled"],
42+
havingValue = "true",
43+
matchIfMissing = false
44+
)
45+
@Bean
46+
fun autoDeploymentOnStartup(processDeployment: ProcessDeployment) =
47+
AutoDeploymentOnStartup(processDeployment = processDeployment)
4748

48-
}
49+
}

spring-boot-starter/src/main/kotlin/dev/bpmcrafters/processengine/worker/process/AutoDeploymentOnStartup.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.springframework.context.ApplicationListener
55

66
/**
77
* Trigger to deploy resources on start-up of application.
8+
* @since 0.5.0
89
*/
910
class AutoDeploymentOnStartup (
1011
private val processDeployment: ProcessDeployment

spring-boot-starter/src/main/kotlin/dev/bpmcrafters/processengine/worker/process/ProcessDeployment.kt

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,38 @@ private val logger = KotlinLogging.logger {}
1515

1616
/**
1717
* Implements configuration of the deployment.
18+
* @since 0.5.0
1819
*/
1920
open class ProcessDeployment(
20-
private val resourcePatternResolver: ResourcePatternResolver,
21-
private val deploymentApi: DeploymentApi,
22-
private val processEngineWorkerDeploymentProperties: ProcessEngineWorkerDeploymentProperties
21+
private val resourcePatternResolver: ResourcePatternResolver,
22+
private val deploymentApi: DeploymentApi,
23+
private val processEngineWorkerDeploymentProperties: ProcessEngineWorkerDeploymentProperties
2324
) {
2425

25-
/**
26-
* Deploys resources, configured via properties.
27-
*/
28-
open fun deployResources(): DeploymentInformation? {
29-
val namedResources = buildList<Resource> {
30-
try {
31-
addAll(resourcePatternResolver.getResources(processEngineWorkerDeploymentProperties.bpmnResourcePattern))
32-
addAll(resourcePatternResolver.getResources(processEngineWorkerDeploymentProperties.dmnResourcePattern))
33-
} catch (e: IOException) {
34-
logger.warn(e) { "PROCESS-ENGINE-WORKER-051: Failed to load resources for deployment." }
35-
}
36-
}.map { resource -> NamedResource(resource.filename ?: "unknown", resource.inputStream) }
37-
38-
if (namedResources.isEmpty()) {
39-
return null
40-
}
41-
42-
return deploymentApi.deploy(
43-
DeployBundleCommand(resources = namedResources)
44-
).get(processEngineWorkerDeploymentProperties.deploymentTimeoutInSeconds, TimeUnit.SECONDS)
45-
.also { deploymentResult ->
46-
logger.info { "PROCESS-ENGINE-WORKER-050: Deployed ${namedResources.size} resources with key ${deploymentResult.deploymentKey}." }
47-
}
26+
/**
27+
* Deploys resources, configured via properties.
28+
*/
29+
open fun deployResources(): DeploymentInformation? {
30+
val namedResources = buildList<Resource> {
31+
try {
32+
addAll(resourcePatternResolver.getResources(processEngineWorkerDeploymentProperties.bpmnResourcePattern))
33+
addAll(resourcePatternResolver.getResources(processEngineWorkerDeploymentProperties.dmnResourcePattern))
34+
} catch (e: IOException) {
35+
logger.warn(e) { "PROCESS-ENGINE-WORKER-051: Failed to load resources for deployment." }
36+
}
37+
}.map { resource -> NamedResource(resource.filename ?: "unknown", resource.inputStream) }
38+
39+
if (namedResources.isEmpty()) {
40+
return null
4841
}
42+
43+
return deploymentApi.deploy(
44+
DeployBundleCommand(resources = namedResources)
45+
).get(processEngineWorkerDeploymentProperties.deploymentTimeoutInSeconds, TimeUnit.SECONDS)
46+
.also { deploymentResult ->
47+
logger.info { "PROCESS-ENGINE-WORKER-050: Deployed ${namedResources.size} resources with key ${deploymentResult.deploymentKey}." }
48+
}
49+
}
4950
}
5051

5152

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dev.bpmcrafters.processengine.worker.registrar
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper
4+
5+
/**
6+
* Helper converting variables from a JSON map to type using Jackson.
7+
* @since 0.0.3
8+
*/
9+
open class JacksonVariableConverter(
10+
private val objectMapper: ObjectMapper
11+
) : VariableConverter {
12+
13+
/**
14+
* Reads from the map-tree structure to a target type.
15+
* @param value map-tree structure.
16+
* @param type target class.
17+
* @return cast value.
18+
*/
19+
override fun <T : Any> mapToType(value: Any?, type: Class<T>): T {
20+
return if (value != null && !type.isInstance(value)) {
21+
objectMapper.readValue(objectMapper.writeValueAsString(value), type)
22+
} else {
23+
type.cast(value)
24+
}
25+
}
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dev.bpmcrafters.processengine.worker.registrar
2+
3+
import dev.bpmcrafters.processengineapi.task.ServiceTaskCompletionApi
4+
import dev.bpmcrafters.processengineapi.task.TaskInformation
5+
import java.lang.reflect.Parameter
6+
import java.util.function.Function
7+
import java.util.function.Predicate
8+
9+
/**
10+
* Parameter resolution strategy.
11+
* @since 0.0.1
12+
*/
13+
interface ParameterResolutionStrategy : Predicate<Parameter>, Function<ParameterResolutionStrategy.Wrapper, Any?> {
14+
15+
/**
16+
* Wraps parameters of parameter and services for determination of the matching resolution strategy.
17+
*/
18+
data class Wrapper(
19+
val parameter: Parameter,
20+
val taskInformation: TaskInformation,
21+
val payload: Map<String, Any>,
22+
val variableConverter: VariableConverter,
23+
val taskCompletionApi: ServiceTaskCompletionApi
24+
)
25+
26+
}

0 commit comments

Comments
 (0)