diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5990cfd94..e7a32bdbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,10 +13,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 @@ -35,7 +35,7 @@ jobs: run: ./mvnw integration-test failsafe:verify -Pitest -B -T4 - name: Upload coverage information - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: token: "${{ secrets.CODECOV_TOKEN }}" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index bece96d6f..78df248a4 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -25,18 +25,6 @@ jobs: # install pip=>20.1 to use "pip cache dir" python3 -m pip install --upgrade pip -# - name: Get pip cache dir -# id: pip-cache -# run: echo "::set-output name=dir::$(pip cache dir)" -# -# - name: Cache dependencies -# uses: actions/cache@v3 -# with: -# path: ${{ steps.pip-cache.outputs.dir }} -# key: ${{ runner.os }}-pip-${{ hashFiles('./docs/requirements.txt') }} -# restore-keys: | -# ${{ runner.os }}-pip- - - name: Install dependencies run: python3 -m pip install -r ./docs/requirements.txt diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml index ff2ec246c..a3d8fbf44 100644 --- a/.github/workflows/release-notes.yml +++ b/.github/workflows/release-notes.yml @@ -9,6 +9,7 @@ jobs: steps: - name: Checkout code uses: actions/checkout@master + - name: Create Release Notes Markdown uses: docker://decathlon/release-notes-generator-action:3.1.5 env: @@ -21,6 +22,7 @@ jobs: echo "RELEASE_NOTES_FILE=$RELEASE_NOTES_FILE" >> $GITHUB_ENV VERSION=$(echo ${{ github.event.milestone.title }} | cut -d' ' -f2) echo "VERSION=$VERSION" >> $GITHUB_ENV + - name: Create a Draft Release Notes on GitHub id: create_release uses: actions/create-release@v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a45fe6a9..a623e5dfc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Setup JDK and Maven - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 17 distribution: 'zulu' @@ -51,7 +51,7 @@ jobs: OSS_CENTRAL_PASSWORD: "${{ secrets.SONATYPE_PASSWORD }}" - name: Upload coverage information to CodeCov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: token: "${{ secrets.CODECOV_TOKEN }}" diff --git a/bom/datapool-dependencies/pom.xml b/bom/datapool-dependencies/pom.xml index 40528bd36..6a16e02dc 100644 --- a/bom/datapool-dependencies/pom.xml +++ b/bom/datapool-dependencies/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-parent - 4.1.4 + 4.1.5 ../parent/pom.xml diff --git a/bom/parent/pom.xml b/bom/parent/pom.xml index ecc3b34cb..b776aec02 100644 --- a/bom/parent/pom.xml +++ b/bom/parent/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-root - 4.1.4 + 4.1.5 ../../pom.xml @@ -19,14 +19,14 @@ 3.1.5 - 7.20.0 + 7.21.0 4.9.4 4.9.0 - 2.0.0 + 2.1.0 - 4.2.0 - 5.2.1 + 4.2.1 + 5.3.1 1.3.1 1.3.1.0 @@ -311,7 +311,7 @@ org.jacoco jacoco-maven-plugin - 0.8.11 + 0.8.12 pre-unit-test @@ -372,7 +372,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 UTF-8 ${java.version} @@ -420,7 +420,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.1 @@ -565,7 +565,7 @@ org.jetbrains.dokka dokka-maven-plugin - 1.9.10 + 1.9.20 attach-javadocs @@ -581,7 +581,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.5.0 + 3.6.0 generate-sources @@ -601,7 +601,7 @@ org.apache.maven.plugins maven-source-plugin - 3.3.0 + 3.3.1 attach-sources @@ -620,7 +620,7 @@ maven-install-plugin - 3.1.1 + 3.1.2 diff --git a/bom/taskpool-dependencies/pom.xml b/bom/taskpool-dependencies/pom.xml index 9a011b103..aabbc4875 100644 --- a/bom/taskpool-dependencies/pom.xml +++ b/bom/taskpool-dependencies/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-parent - 4.1.4 + 4.1.5 ../parent/pom.xml diff --git a/core/bus-jackson/pom.xml b/core/bus-jackson/pom.xml index f6f428fbe..bbb0ca60c 100755 --- a/core/bus-jackson/pom.xml +++ b/core/bus-jackson/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-parent - 4.1.4 + 4.1.5 ../../bom/parent/pom.xml diff --git a/core/bus-jackson/src/main/kotlin/io/holunda/polyflow/bus/jackson/JsonAutoDetectAnyVisibility.kt b/core/bus-jackson/src/main/kotlin/io/holunda/polyflow/bus/jackson/JsonAutoDetectAnyVisibility.kt new file mode 100644 index 000000000..fc79c2fb9 --- /dev/null +++ b/core/bus-jackson/src/main/kotlin/io/holunda/polyflow/bus/jackson/JsonAutoDetectAnyVisibility.kt @@ -0,0 +1,9 @@ +package io.holunda.polyflow.bus.jackson + +import com.fasterxml.jackson.annotation.JsonAutoDetect + +/** + * Allow serialization of all fields. (Also private fields!) + */ +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +class JsonAutoDetectAnyVisibility diff --git a/core/datapool/datapool-api/pom.xml b/core/datapool/datapool-api/pom.xml index 5d7a669f9..f14a7909e 100755 --- a/core/datapool/datapool-api/pom.xml +++ b/core/datapool/datapool-api/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-datapool-parent - 4.1.4 + 4.1.5 polyflow-datapool-api diff --git a/core/datapool/datapool-core/pom.xml b/core/datapool/datapool-core/pom.xml index 661917e5d..dcbaa5ab4 100644 --- a/core/datapool/datapool-core/pom.xml +++ b/core/datapool/datapool-core/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-datapool-parent - 4.1.4 + 4.1.5 polyflow-datapool-core @@ -40,12 +40,11 @@ dom4j 2.1.4 - io.holunda.polyflow polyflow-bus-jackson - test + org.springframework.boot spring-boot-starter-test diff --git a/core/datapool/datapool-core/src/main/kotlin/io/holunda/polyflow/datapool/core/DataPoolCoreAxonConfiguration.kt b/core/datapool/datapool-core/src/main/kotlin/io/holunda/polyflow/datapool/core/DataPoolCoreAxonConfiguration.kt index d1acd8734..a3f6fd958 100755 --- a/core/datapool/datapool-core/src/main/kotlin/io/holunda/polyflow/datapool/core/DataPoolCoreAxonConfiguration.kt +++ b/core/datapool/datapool-core/src/main/kotlin/io/holunda/polyflow/datapool/core/DataPoolCoreAxonConfiguration.kt @@ -1,5 +1,7 @@ package io.holunda.polyflow.datapool.core +import com.fasterxml.jackson.databind.ObjectMapper +import io.holunda.polyflow.bus.jackson.JsonAutoDetectAnyVisibility import io.holunda.polyflow.datapool.core.business.CreateOrUpdateCommandHandler import io.holunda.polyflow.datapool.core.business.DataEntryAggregate import io.holunda.polyflow.datapool.core.business.upcaster.DataEntryCreatedEventUpcaster @@ -13,6 +15,7 @@ import org.axonframework.eventsourcing.SnapshotTriggerDefinition import org.axonframework.eventsourcing.Snapshotter import org.axonframework.eventsourcing.eventstore.EventStore import org.axonframework.messaging.annotation.ParameterResolverFactory +import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.context.annotation.Bean @@ -98,5 +101,15 @@ class DataPoolCoreAxonConfiguration { */ @Bean(DATA_ENTRY_CACHE) fun dataEntryCache(): Cache = WeakReferenceCache() + + @Autowired + fun configureJackson(objectMapper: ObjectMapper) { + objectMapper.configurePolyflowJacksonObjectMapperForDatapool() + } +} + +fun ObjectMapper.configurePolyflowJacksonObjectMapperForDatapool(): ObjectMapper { + addMixIn(DataEntryAggregate::class.java, JsonAutoDetectAnyVisibility::class.java) + return this } diff --git a/core/datapool/datapool-core/src/test/kotlin/io/holunda/polyflow/datapool/core/business/DataEntryAggregateTest.kt b/core/datapool/datapool-core/src/test/kotlin/io/holunda/polyflow/datapool/core/business/DataEntryAggregateTest.kt index 262004518..2f6d34f81 100644 --- a/core/datapool/datapool-core/src/test/kotlin/io/holunda/polyflow/datapool/core/business/DataEntryAggregateTest.kt +++ b/core/datapool/datapool-core/src/test/kotlin/io/holunda/polyflow/datapool/core/business/DataEntryAggregateTest.kt @@ -1,7 +1,13 @@ package io.holunda.polyflow.datapool.core.business +import com.fasterxml.jackson.databind.ObjectMapper import io.holunda.camunda.taskpool.api.business.* +import io.holunda.polyflow.bus.jackson.JsonAutoDetectAnyVisibility +import io.holunda.polyflow.bus.jackson.configurePolyflowJacksonObjectMapper import io.holunda.polyflow.datapool.core.DeletionStrategy +import io.holunda.polyflow.datapool.core.configurePolyflowJacksonObjectMapperForDatapool +import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat import org.axonframework.eventsourcing.AggregateDeletedException import org.axonframework.test.aggregate.AggregateTestFixture import org.camunda.bpm.engine.variable.Variables @@ -353,5 +359,53 @@ class DataEntryAggregateTest { ) } + @Test + fun `should serialize and deserialize an empty aggregate`() { + // GIVEN an object mapper and an empty aggregate + val objectMapper = ObjectMapper().configurePolyflowJacksonObjectMapper() + val dataEntryAggregate = DataEntryAggregate() + + // WHEN we serialize and deserialize it + val serializedObj = objectMapper.writeValueAsString(dataEntryAggregate) + objectMapper.readValue(serializedObj, DataEntryAggregate::class.java) + // THEN no problem should occur + } + + @Test + fun `should serialize and deserialize an aggregate with data`() { + // GIVEN an object mapper and a filled aggregate + val objectMapper = ObjectMapper() + .configurePolyflowJacksonObjectMapper() + .configurePolyflowJacksonObjectMapperForDatapool() + + val dataEntryAggregate = DataEntryAggregate().apply { + on( + DataEntryCreatedEvent( + entryId = UUID.randomUUID().toString(), + entryType = "io.holunda.My", + name = "Some name", + type = "Another", + applicationName = "Different application", + ) + ) + } + val dataIdentityValue = dataEntryAggregate.getDataIdentityValueForTest() + + // WHEN we serialize and deserialize it + val serializedObj = objectMapper.writeValueAsString(dataEntryAggregate) + val deserializedObj = objectMapper.readValue(serializedObj, DataEntryAggregate::class.java) + + // THEN no problem should occur + assertThat(deserializedObj.getDataIdentityValueForTest()).isEqualTo(dataIdentityValue) + } + +} + +private fun DataEntryAggregate.getDataIdentityValueForTest(): String? { + return javaClass.getDeclaredField("dataIdentity").let { + it.isAccessible = true + val value = it.get(this) as String? + return@let value + } } diff --git a/core/datapool/datapool-event/pom.xml b/core/datapool/datapool-event/pom.xml index 3688e0fda..b08a6b98b 100755 --- a/core/datapool/datapool-event/pom.xml +++ b/core/datapool/datapool-event/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-datapool-parent - 4.1.4 + 4.1.5 polyflow-datapool-event diff --git a/core/datapool/pom.xml b/core/datapool/pom.xml index 6bffafc10..9f663ca3c 100755 --- a/core/datapool/pom.xml +++ b/core/datapool/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-parent - 4.1.4 + 4.1.5 ../../bom/parent/pom.xml diff --git a/core/spring-utils/pom.xml b/core/spring-utils/pom.xml index 3af7ae9f2..57602cef2 100755 --- a/core/spring-utils/pom.xml +++ b/core/spring-utils/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-parent - 4.1.4 + 4.1.5 ../../bom/parent/pom.xml diff --git a/core/taskpool/pom.xml b/core/taskpool/pom.xml index a69b6e362..69037f002 100755 --- a/core/taskpool/pom.xml +++ b/core/taskpool/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-parent - 4.1.4 + 4.1.5 ../../bom/parent/pom.xml diff --git a/core/taskpool/taskpool-api/pom.xml b/core/taskpool/taskpool-api/pom.xml index 0d905573f..49bd0b6ff 100755 --- a/core/taskpool/taskpool-api/pom.xml +++ b/core/taskpool/taskpool-api/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-taskpool-parent - 4.1.4 + 4.1.5 polyflow-taskpool-api diff --git a/core/taskpool/taskpool-core/pom.xml b/core/taskpool/taskpool-core/pom.xml index a03337f06..96e51aeac 100755 --- a/core/taskpool/taskpool-core/pom.xml +++ b/core/taskpool/taskpool-core/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-taskpool-parent - 4.1.4 + 4.1.5 polyflow-taskpool-core diff --git a/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/JacksonExtensions.kt b/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/JacksonExtensions.kt deleted file mode 100644 index 090af6d87..000000000 --- a/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/JacksonExtensions.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.holunda.polyflow.taskpool.core - -import com.fasterxml.jackson.databind.ObjectMapper -import io.holunda.polyflow.bus.jackson.configurePolyflowJacksonObjectMapper - -/** - * Configures object mapper. - */ -@Deprecated( - replaceWith = ReplaceWith("io.holunda.polyflow.bus.jackson.configurePolyflowJacksonObjectMapper()"), - message = "Moved to separate artifact polyflow-bus-jackson" -) -fun ObjectMapper.configureTaskpoolJacksonObjectMapper(): ObjectMapper = configurePolyflowJacksonObjectMapper() diff --git a/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/TaskPoolCoreConfiguration.kt b/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/TaskPoolCoreConfiguration.kt index 6b31cffed..5fe428ddc 100755 --- a/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/TaskPoolCoreConfiguration.kt +++ b/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/TaskPoolCoreConfiguration.kt @@ -1,13 +1,18 @@ package io.holunda.polyflow.taskpool.core +import com.fasterxml.jackson.databind.ObjectMapper +import io.holunda.polyflow.bus.jackson.JsonAutoDetectAnyVisibility import io.holunda.polyflow.taskpool.core.process.ProcessDefinitionAggregate import io.holunda.polyflow.taskpool.core.process.ProcessInstanceAggregate import io.holunda.polyflow.taskpool.core.task.TaskAggregate +import org.axonframework.common.caching.Cache +import org.axonframework.common.caching.WeakReferenceCache import org.axonframework.eventsourcing.EventSourcingRepository import org.axonframework.eventsourcing.eventstore.EventStore import org.axonframework.messaging.annotation.ParameterResolverFactory import org.axonframework.modelling.command.Aggregate import org.axonframework.modelling.command.AggregateNotFoundException +import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Bean import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration @@ -22,6 +27,7 @@ class TaskPoolCoreConfiguration { companion object { const val TASK_AGGREGATE_REPOSITORY = "taskAggregateRepository" + const val TASK_CACHE = "taskCache" const val PROCESS_DEFINITION_AGGREGATE_REPOSITORY = "processDefinitionAggregateRepository" const val PROCESS_INSTANCE_AGGREGATE_REPOSITORY = "processInstanceAggregateRepository" } @@ -62,6 +68,16 @@ class TaskPoolCoreConfiguration { .build() } + @Autowired + fun configureJackson(objectMapper: ObjectMapper) { + objectMapper.configurePolyflowJacksonObjectMapperForTaskPool() + } + + /** + * Use weak reference cache. + */ + @Bean(TASK_CACHE) + fun taskCache(): Cache = WeakReferenceCache() } /** @@ -89,3 +105,8 @@ fun Optional.ifPresentOrElse(presentConsumer: (T) -> Unit, missingCallbac } } +fun ObjectMapper.configurePolyflowJacksonObjectMapperForTaskPool(): ObjectMapper { + addMixIn(TaskAggregate::class.java, JsonAutoDetectAnyVisibility::class.java) + return this +} + diff --git a/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/process/ProcessInstanceVariablesChangeHandler.kt b/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/process/ProcessInstanceVariablesChangeHandler.kt index b5cfb745c..aa15b0904 100644 --- a/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/process/ProcessInstanceVariablesChangeHandler.kt +++ b/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/process/ProcessInstanceVariablesChangeHandler.kt @@ -7,7 +7,7 @@ import org.springframework.context.annotation.Lazy import org.springframework.stereotype.Component /** - * This handler makes sure that an update of variables can be send without a create of the process instance.. + * This handler makes sure that an update of variables can be sent without a create of the process instance. */ @Component class ProcessInstanceVariablesChangeHandler( diff --git a/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/task/TaskAggregate.kt b/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/task/TaskAggregate.kt index b7554eaa2..087d1d4cf 100755 --- a/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/task/TaskAggregate.kt +++ b/core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/task/TaskAggregate.kt @@ -15,7 +15,10 @@ import org.axonframework.spring.stereotype.Aggregate /** * Main representation of the tasks available in the system. */ -@Aggregate(repository = TaskPoolCoreConfiguration.TASK_AGGREGATE_REPOSITORY) +@Aggregate( + repository = TaskPoolCoreConfiguration.TASK_AGGREGATE_REPOSITORY, + cache = TaskPoolCoreConfiguration.TASK_CACHE, +) class TaskAggregate() { companion object : KLogging() diff --git a/core/taskpool/taskpool-event/pom.xml b/core/taskpool/taskpool-event/pom.xml index 2331d8823..98afc50d6 100644 --- a/core/taskpool/taskpool-event/pom.xml +++ b/core/taskpool/taskpool-event/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-taskpool-parent - 4.1.4 + 4.1.5 polyflow-taskpool-event diff --git a/docs/examples/scenarios/single-node.md b/docs/examples/scenarios/single-node.md index 2eb909af7..9f852cb42 100644 --- a/docs/examples/scenarios/single-node.md +++ b/docs/examples/scenarios/single-node.md @@ -16,7 +16,7 @@ Before you begin, please build the entire project with `./mvnw clean install` fr ### Start The demo application consists of one Maven module which can be started by running from command line in -the `examples/scenarios/single-node` directory using Maven. Alternatively you can start the packaged application using: +the `examples/scenarios/single-node-jpa` directory using Maven. Alternatively you can start the packaged application using: ```bash java -jar target/*.jar @@ -24,6 +24,6 @@ java -jar target/*.jar ## Useful URLs -* [http://localhost:8080/taskpool/](http://localhost:8080/polyflow/) +* [http://localhost:8080/polyflow/](http://localhost:8080/polyflow/) * [http://localhost:8080/swagger-ui/](http://localhost:8080/swagger-ui/) * [http://localhost:8080/camunda/app/tasklist/default/](http://localhost:8080/camunda/app/tasklist/default/) diff --git a/integration/camunda-bpm/engine-client/pom.xml b/integration/camunda-bpm/engine-client/pom.xml index 17e931e5d..025f5a3aa 100644 --- a/integration/camunda-bpm/engine-client/pom.xml +++ b/integration/camunda-bpm/engine-client/pom.xml @@ -5,7 +5,7 @@ io.holunda.polyflow polyflow-integration-camunda-bpm-engine-parent - 4.1.4 + 4.1.5 polyflow-camunda-bpm-engine-client diff --git a/integration/camunda-bpm/pom.xml b/integration/camunda-bpm/pom.xml index 70e873fd1..293013459 100644 --- a/integration/camunda-bpm/pom.xml +++ b/integration/camunda-bpm/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-parent - 4.1.4 + 4.1.5 ../../bom/parent/pom.xml @@ -15,9 +15,9 @@ pom - 7.20.0 + 7.21.0 ${camunda-bpm.version} - 7.20.0 + 7.21.0 diff --git a/integration/camunda-bpm/springboot-autoconfigure/pom.xml b/integration/camunda-bpm/springboot-autoconfigure/pom.xml index b98124970..2931fd03c 100755 --- a/integration/camunda-bpm/springboot-autoconfigure/pom.xml +++ b/integration/camunda-bpm/springboot-autoconfigure/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-integration-camunda-bpm-engine-parent - 4.1.4 + 4.1.5 polyflow-camunda-bpm-springboot-autoconfigure diff --git a/integration/camunda-bpm/springboot-starter/pom.xml b/integration/camunda-bpm/springboot-starter/pom.xml index 4bc0ce3a7..d3934a85c 100755 --- a/integration/camunda-bpm/springboot-starter/pom.xml +++ b/integration/camunda-bpm/springboot-starter/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-integration-camunda-bpm-engine-parent - 4.1.4 + 4.1.5 polyflow-camunda-bpm-springboot-starter diff --git a/integration/camunda-bpm/taskpool-collector/pom.xml b/integration/camunda-bpm/taskpool-collector/pom.xml index 4370c2de7..5e10c70c6 100755 --- a/integration/camunda-bpm/taskpool-collector/pom.xml +++ b/integration/camunda-bpm/taskpool-collector/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-integration-camunda-bpm-engine-parent - 4.1.4 + 4.1.5 polyflow-camunda-bpm-taskpool-collector diff --git a/integration/camunda-bpm/taskpool-job-sender/pom.xml b/integration/camunda-bpm/taskpool-job-sender/pom.xml index 33e7607c7..b4dec28f5 100755 --- a/integration/camunda-bpm/taskpool-job-sender/pom.xml +++ b/integration/camunda-bpm/taskpool-job-sender/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-integration-camunda-bpm-engine-parent - 4.1.4 + 4.1.5 polyflow-camunda-bpm-taskpool-job-sender diff --git a/integration/common/datapool-sender/pom.xml b/integration/common/datapool-sender/pom.xml index 548d9dbbf..b036d438d 100755 --- a/integration/common/datapool-sender/pom.xml +++ b/integration/common/datapool-sender/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-integration-common-parent - 4.1.4 + 4.1.5 polyflow-datapool-sender diff --git a/integration/common/pom.xml b/integration/common/pom.xml index 1e8219e8d..e495bf72d 100755 --- a/integration/common/pom.xml +++ b/integration/common/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-parent - 4.1.4 + 4.1.5 ../../bom/parent/pom.xml diff --git a/integration/common/tasklist-url-resolver/pom.xml b/integration/common/tasklist-url-resolver/pom.xml index edec9d1d2..12fb3a55c 100644 --- a/integration/common/tasklist-url-resolver/pom.xml +++ b/integration/common/tasklist-url-resolver/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-integration-common-parent - 4.1.4 + 4.1.5 polyflow-tasklist-url-resolver diff --git a/integration/common/taskpool-sender/pom.xml b/integration/common/taskpool-sender/pom.xml index 4add0f46b..5d0a674fb 100755 --- a/integration/common/taskpool-sender/pom.xml +++ b/integration/common/taskpool-sender/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-integration-common-parent - 4.1.4 + 4.1.5 polyflow-taskpool-sender diff --git a/integration/common/variable-serializer/pom.xml b/integration/common/variable-serializer/pom.xml index 3e31e3ca2..73f98c4d5 100755 --- a/integration/common/variable-serializer/pom.xml +++ b/integration/common/variable-serializer/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-integration-common-parent - 4.1.4 + 4.1.5 polyflow-variable-serializer diff --git a/integration/common/variable-serializer/src/main/kotlin/VariableSerializer.kt b/integration/common/variable-serializer/src/main/kotlin/VariableSerializer.kt index 4f20dab4d..e02c34eca 100644 --- a/integration/common/variable-serializer/src/main/kotlin/VariableSerializer.kt +++ b/integration/common/variable-serializer/src/main/kotlin/VariableSerializer.kt @@ -40,19 +40,22 @@ typealias JsonPathFilterFunction = (path: String) -> Boolean /** - * Converts a deep map structure representing the payload into a map of one level keyed by the JSON path and valued by the value. - * The map might contain primitive types or maps as value. + * Converts a deep list of pairs representing the payload into a list of pairs of one level keyed by the JSON path and + * valued by the value. A map structure is not sufficient because there can be multiple (different) values for the same + * path. For example a pair with a list value of (customer, [foo, bar]) would be converted to the two pairs + * (customer, foo) and (customer, bar). + * Note: The initial map might contain primitive types, maps or lists as values. * @param limit limit of levels to convert. Defaults to -1 meaning there is no limit. * @param filters filter object to identify properties to include into the result. */ -fun VariableMap.toJsonPathsWithValues(limit: Int = -1, filters: List> = emptyList()): Map { - val pathsWithValues: List> = this.entries.map { - it.toJsonPathWithValue(prefix = "", limit = limit, filter = filters).toMap().toMutableMap() - } - return pathsWithValues.reduceOrNull { result, memberList -> result.apply { putAll(memberList) } }?.toMap() ?: mapOf() +fun VariableMap.toJsonPathsWithValues(limit: Int = -1, filters: List> = emptyList()): Set> { + return this.entries + .map { it.toPair() } + .map { it.toJsonPathWithValue(prefix = "", limit = limit, filter = filters) } + .flatten().toSet() } -internal fun MutableMap.MutableEntry.toJsonPathWithValue( +internal fun Pair.toJsonPathWithValue( prefix: String = "", limit: Int = -1, filter: List> @@ -64,12 +67,12 @@ internal fun MutableMap.MutableEntry.toJsonPathWithValue( } // compose the path key val key = if (prefix == "") { - this.key + this.first } else { - "$prefix.${this.key}" + "$prefix.${this.first}" } - val value = this.value + val value = this.second return if (value != null && value.isPrimitiveType()) { // check the filters @@ -86,7 +89,12 @@ internal fun MutableMap.MutableEntry.toJsonPathWithValue( listOf(key to value) } else if (value is Map<*, *>) { @Suppress("UNCHECKED_CAST") - (value as Map).toMutableMap().entries.map { it.toJsonPathWithValue(key, limit, filter) }.flatten() + (value as Map).entries + .map { it.toPair() } + .map { it.toJsonPathWithValue(key, limit, filter) } + .flatten() + } else if (value is List<*>) { + value.map { (key to it).toJsonPathWithValue(prefix, limit, filter) }.flatten() } else { // ignore complex objects listOf() diff --git a/integration/common/variable-serializer/src/test/kotlin/JsonPathWithValueTest.kt b/integration/common/variable-serializer/src/test/kotlin/JsonPathWithValueTest.kt index 5aa7661b6..d7a5e94fd 100644 --- a/integration/common/variable-serializer/src/test/kotlin/JsonPathWithValueTest.kt +++ b/integration/common/variable-serializer/src/test/kotlin/JsonPathWithValueTest.kt @@ -41,10 +41,10 @@ internal class JsonPathWithValueTest { val result = payload.toJsonPathsWithValues(limit = -1) - assertThat(result.keys).containsExactlyInAnyOrderElementsOf(payload.keys) + assertThat(result.keys()).containsExactlyInAnyOrderElementsOf(payload.keys) payload.entries.forEach { - assertThat(result).containsKey(it.key) - assertThat(result[it.key]).isEqualTo(it.value) + assertThat(result.keys()).contains(it.key) + assertThat(result.first { entry -> entry.first == it.key }.second).isEqualTo(it.value) } } @@ -72,7 +72,7 @@ internal class JsonPathWithValueTest { val result = deep.toJsonPathsWithValues(limit = -1) - assertThat(result.keys).containsExactlyInAnyOrderElementsOf( + assertThat(result.keys()).containsExactlyInAnyOrderElementsOf( flat.keys.plus( listOf( "key-map.child1", @@ -82,13 +82,13 @@ internal class JsonPathWithValueTest { ) ) flat.entries.forEach { - assertThat(result).containsKey(it.key) - assertThat(result[it.key]).isEqualTo(it.value) + assertThat(result.keys()).contains(it.key) + assertThat(result.first { entry -> entry.first == it.key }.second).isEqualTo(it.value) } - assertThat(result["key-map.child1"]).isEqualTo("string") - assertThat(result["key-map.child2.grand-child1"]).isEqualTo("grand-child-value") - assertThat(result["key-map.child2.grand-child2"]).isEqualTo(451.01F) + assertThat(result).contains("key-map.child1" to "string") + assertThat(result).contains("key-map.child2.grand-child1" to "grand-child-value") + assertThat(result).contains("key-map.child2.grand-child2" to 451.01F) } @Test @@ -115,7 +115,7 @@ internal class JsonPathWithValueTest { val result = deep.toJsonPathsWithValues(limit = 1) - assertThat(result.keys).containsExactlyInAnyOrderElementsOf( + assertThat(result.keys()).containsExactlyInAnyOrderElementsOf( flat.keys.plus( listOf( "key-map.child1" @@ -123,11 +123,11 @@ internal class JsonPathWithValueTest { ) ) flat.entries.forEach { - assertThat(result).containsKey(it.key) - assertThat(result[it.key]).isEqualTo(it.value) + assertThat(result.keys()).contains(it.key) + assertThat(result).contains(it.key to it.value) } - assertThat(result["key-map.child1"]).isEqualTo("string") - assertThat(result["key-map.child2"]).isNull() + assertThat(result).contains("key-map.child1" to "string") + assertThat(result.keys()).doesNotContain("key-map.child2") } @Test @@ -145,7 +145,7 @@ internal class JsonPathWithValueTest { put("key", "value") put("to-ignore", "should not be there") } - assertThat(payload.toJsonPathsWithValues(filters = listOf(eqExclude("to-ignore")))).containsOnlyKeys("key") + assertThat(payload.toJsonPathsWithValues(filters = listOf(eqExclude("to-ignore"))).keys()).containsOnly("key") } @@ -155,7 +155,7 @@ internal class JsonPathWithValueTest { put("key", "value") put("to-ignore", "should not be there") } - assertThat(payload.toJsonPathsWithValues(filters = listOf(eqInclude("key")))).containsOnlyKeys("key") + assertThat(payload.toJsonPathsWithValues(filters = listOf(eqInclude("key"))).keys()).containsOnly("key") } @Test @@ -172,8 +172,8 @@ internal class JsonPathWithValueTest { eqInclude("include2"), eqExclude("to-ignore") ) - ) - ).containsOnlyKeys("include1", "include2") + ).keys() + ).containsOnly("include1", "include2") } @Test @@ -188,8 +188,8 @@ internal class JsonPathWithValueTest { eqInclude("include1.key"), eqInclude("include2"), ) - ) - ).containsOnlyKeys("include1.key", "include2") + ).keys() + ).containsOnly("include1.key", "include2") } @@ -199,7 +199,7 @@ internal class JsonPathWithValueTest { put("key", "value") put("other", "value2") } - assertThat(payload.toJsonPathsWithValues(filters = listOf(all()))).containsOnlyKeys("key", "other") + assertThat(payload.toJsonPathsWithValues(filters = listOf(all())).keys()).containsOnly("key", "other") } @Test @@ -211,4 +211,46 @@ internal class JsonPathWithValueTest { assertThat(payload.toJsonPathsWithValues(filters = listOf(none()))).isEmpty() } + @Test + fun `should map list to multiple pairs`() { + val payload = createVariables().apply { + put("multiple", listOf("value-1", "value-2")) + } + + val result = payload.toJsonPathsWithValues() + + assertThat(result).hasSize(2) + assertThat(result).contains("multiple" to "value-1") + assertThat(result).contains("multiple" to "value-2") + } + + @Test + fun `should map list of lists`() { + val payload = createVariables().apply { + put("multiple", listOf(listOf("value-1", "value-2"), listOf("value-3", "value-4"))) + } + val result = payload.toJsonPathsWithValues() + + assertThat(result).hasSize(4) + assertThat(result).contains("multiple" to "value-1") + assertThat(result).contains("multiple" to "value-2") + assertThat(result).contains("multiple" to "value-3") + assertThat(result).contains("multiple" to "value-4") + } + + @Test + fun `should map list of maps`() { + val payload = createVariables().apply { + put("multiple", listOf(mapOf("deepKey1" to "value-1"), mapOf("deepKey2" to "value-2"))) + } + val result = payload.toJsonPathsWithValues() + + assertThat(result).hasSize(2) + assertThat(result).contains("multiple.deepKey1" to "value-1") + assertThat(result).contains("multiple.deepKey2" to "value-2") + } +} + +internal fun Set>.keys(): List { + return this.map { it.first } } diff --git a/integration/common/variable-serializer/src/test/kotlin/VariableSerializerTest.kt b/integration/common/variable-serializer/src/test/kotlin/VariableSerializerTest.kt index f636d14c9..9d423d687 100755 --- a/integration/common/variable-serializer/src/test/kotlin/VariableSerializerTest.kt +++ b/integration/common/variable-serializer/src/test/kotlin/VariableSerializerTest.kt @@ -124,4 +124,15 @@ class VariableSerializerTest { val elements = expectedPojoMap[Pojo1::anotherKey.name] as List> assertThat(elements).containsExactly(linkedMapOf(Pojo2::keyZUZUZ.name to "p2", Pojo2::children.name to listOf())) } + + @Test + fun `should transform list of primitives to map`() { + val map = createVariables() + .putValue("many", listOf("value1", "value2")) + + val result = serialize(map, mapper) + + assertThat(result).containsKey("many") + assertThat(result["many"]).isEqualTo(listOf("value1", "value2")) + } } diff --git a/pom.xml b/pom.xml index 880dd44c6..6a6f66ca2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.holunda.polyflow polyflow-root - 4.1.4 + 4.1.5 pom POM: ${project.artifactId} @@ -19,7 +19,7 @@ 17 ${java.version} - 1.9.22 + 2.0.0 ${java.version} true 3.0.5 @@ -130,7 +130,7 @@ org.apache.maven.plugins maven-deploy-plugin - 3.1.1 + 3.1.2 true @@ -138,7 +138,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.13 + 1.7.0 default-deploy @@ -158,7 +158,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.1.0 + 3.2.4 diff --git a/view/form-url-resolver/pom.xml b/view/form-url-resolver/pom.xml index eba3cbfd4..73dabab6a 100644 --- a/view/form-url-resolver/pom.xml +++ b/view/form-url-resolver/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-view-parent - 4.1.4 + 4.1.5 polyflow-form-url-resolver @@ -26,7 +26,7 @@ org.apache.commons commons-text - 1.11.0 + 1.12.0 org.springframework.boot diff --git a/view/jpa/pom.xml b/view/jpa/pom.xml index b17f51ddb..20f64f170 100644 --- a/view/jpa/pom.xml +++ b/view/jpa/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-view-parent - 4.1.4 + 4.1.5 polyflow-view-jpa @@ -233,12 +233,12 @@ com.microsoft.sqlserver mssql-jdbc - 12.6.1.jre11 + 12.7.0.jre11-preview org.postgresql postgresql - 42.7.2 + 42.7.3 diff --git a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/payload/PayloadAttribute.kt b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/payload/PayloadAttribute.kt index 6acdd0ae3..3c3e2f91e 100644 --- a/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/payload/PayloadAttribute.kt +++ b/view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/payload/PayloadAttribute.kt @@ -20,7 +20,7 @@ class PayloadAttribute( * Factory method to create payload attributes out of map entries. * Check VariableSerializer methods how such map entries can be created. */ - operator fun invoke(entry: Map.Entry) = PayloadAttribute(path = entry.key, value = entry.value.toString()) + operator fun invoke(entry: Pair) = PayloadAttribute(path = entry.first, value = entry.second.toString()) } override fun equals(other: Any?): Boolean { diff --git a/view/mongo/pom.xml b/view/mongo/pom.xml index 98ea34689..1dfc365be 100644 --- a/view/mongo/pom.xml +++ b/view/mongo/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-view-parent - 4.1.4 + 4.1.5 polyflow-view-mongo diff --git a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/TaskChangeTrackerTest.kt b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/TaskChangeTrackerTest.kt index bed86afda..ec0de1012 100644 --- a/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/TaskChangeTrackerTest.kt +++ b/view/mongo/src/test/kotlin/io/holunda/polyflow/view/mongo/service/TaskChangeTrackerTest.kt @@ -33,7 +33,6 @@ import java.time.Clock import java.time.Duration import java.time.Instant import java.time.ZoneOffset -import java.util.* internal class TaskChangeTrackerTest { private val taskRepository: TaskRepository = mock() @@ -224,6 +223,7 @@ internal class TaskChangeTrackerTest { @Test fun `schedules job for deleting leftover tasks`() { + publisherForResumeToken(null) properties = properties.copy( changeStream = properties.changeStream.copy( clearDeletedTasks = properties.changeStream.clearDeletedTasks.copy( @@ -246,11 +246,11 @@ internal class TaskChangeTrackerTest { taskChangeTracker.initCleanupJob() verify(scheduler).schedule(deleteRunnableCaptor.capture(), triggerCaptor.capture()) val trigger = triggerCaptor.firstValue - assertThat(trigger.nextExecutionTime(SimpleTriggerContext(Clock.fixed(Instant.EPOCH, ZoneOffset.UTC)).apply { + assertThat(trigger.nextExecution(SimpleTriggerContext(Clock.fixed(Instant.EPOCH, ZoneOffset.UTC)).apply { update( - Date.from(Instant.EPOCH.minus(Duration.ofHours(24))), - Date.from(Instant.EPOCH.minus(Duration.ofHours(24))), - Date.from(Instant.EPOCH.minus(Duration.ofHours(23))) + Instant.EPOCH.minus(Duration.ofHours(24)), + Instant.EPOCH.minus(Duration.ofHours(24)), + Instant.EPOCH.minus(Duration.ofHours(23)) ) })).isBetween(Instant.EPOCH, Instant.EPOCH.plus(Duration.ofHours(1))) deleteRunnableCaptor.firstValue.run() @@ -287,6 +287,9 @@ internal class TaskChangeTrackerTest { null, null, null, + null, + null, + null, null ), TaskDocument::class.java, converter ) diff --git a/view/pom.xml b/view/pom.xml index ed99dbd21..9ae7f1556 100644 --- a/view/pom.xml +++ b/view/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-parent - 4.1.4 + 4.1.5 ../bom/parent/pom.xml diff --git a/view/simple/pom.xml b/view/simple/pom.xml index ecadce72e..f42e6e86d 100755 --- a/view/simple/pom.xml +++ b/view/simple/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-view-parent - 4.1.4 + 4.1.5 polyflow-view-simple diff --git a/view/view-api-client/pom.xml b/view/view-api-client/pom.xml index 490fe5aa0..7404fe2b8 100755 --- a/view/view-api-client/pom.xml +++ b/view/view-api-client/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-view-parent - 4.1.4 + 4.1.5 polyflow-view-api-client diff --git a/view/view-api/pom.xml b/view/view-api/pom.xml index 2259f8c05..50563a3ba 100755 --- a/view/view-api/pom.xml +++ b/view/view-api/pom.xml @@ -6,7 +6,7 @@ io.holunda.polyflow polyflow-view-parent - 4.1.4 + 4.1.5 polyflow-view-api