├── .codacy.yaml ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── 1_bug_report.md │ └── 2_feature_request.md ├── dependabot.yml ├── release-notes.yml └── workflows │ ├── ci.yml │ ├── codacy.yml │ ├── docs.yml │ ├── release-notes.yml │ └── release.yml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── LICENSE ├── README.md ├── SECURITY.md ├── bom ├── datapool-dependencies │ └── pom.xml ├── parent │ └── pom.xml └── taskpool-dependencies │ └── pom.xml ├── codecov.yml ├── core ├── bus-jackson │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── polyflow │ │ │ │ └── bus │ │ │ │ └── jackson │ │ │ │ ├── DataEntryStateTypeMappingModule.kt │ │ │ │ ├── JacksonExtensions.kt │ │ │ │ ├── JsonAutoDetectAnyVisibility.kt │ │ │ │ ├── KotlinTypeInfo.kt │ │ │ │ ├── VariableMapTypeMappingModule.kt │ │ │ │ └── config │ │ │ │ └── FallbackPayloadObjectMapperAutoConfiguration.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── spring │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ └── test │ │ └── kotlin │ │ └── io │ │ └── holunda │ │ └── polyflow │ │ ├── bus │ │ └── jackson │ │ │ ├── CreateTaskCommandSerializationTest.kt │ │ │ ├── DataEntryCommandsSerializationTest.kt │ │ │ └── DeserializersTest.kt │ │ └── view │ │ └── query │ │ ├── data │ │ └── DataEntryQueriesDeserializationTest.kt │ │ ├── process │ │ ├── ProcessDefinitionQueriesDeserializationTest.kt │ │ ├── ProcessInstanceQueriesDeserializationTest.kt │ │ └── variable │ │ │ └── ProcessInstanceQueriesDeserializationTest.kt │ │ └── task │ │ └── TaskQueriesDeserializationTest.kt ├── datapool │ ├── datapool-api │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── kotlin │ │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── camunda │ │ │ │ └── taskpool │ │ │ │ └── api │ │ │ │ └── business │ │ │ │ ├── AuthorizationChange.kt │ │ │ │ ├── DataEntryChange.kt │ │ │ │ ├── DataEntryCommands.kt │ │ │ │ ├── DataEntryState.kt │ │ │ │ ├── DataIdentity.kt │ │ │ │ ├── Modification.kt │ │ │ │ ├── ProcessingType.kt │ │ │ │ ├── WithCorrelations.kt │ │ │ │ └── WithPayload.kt │ │ │ └── test │ │ │ └── kotlin │ │ │ └── io │ │ │ └── holunda │ │ │ └── camunda │ │ │ └── taskpool │ │ │ └── api │ │ │ └── business │ │ │ └── ProcessingTypeTest.kt │ ├── datapool-core │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── kotlin │ │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── polyflow │ │ │ │ └── datapool │ │ │ │ ├── Helpers.kt │ │ │ │ └── core │ │ │ │ ├── DataPoolCoreAxonConfiguration.kt │ │ │ │ ├── DataPoolCoreConfiguration.kt │ │ │ │ ├── DataPoolProperties.kt │ │ │ │ ├── DeletionStrategy.kt │ │ │ │ ├── DeletionStrategyValue.kt │ │ │ │ ├── EnablePolyflowDataPool.kt │ │ │ │ ├── business │ │ │ │ ├── CreateOrUpdateCommandHandler.kt │ │ │ │ ├── DataEntryAggregate.kt │ │ │ │ └── upcaster │ │ │ │ │ ├── DataEntryEventUpcaster.kt │ │ │ │ │ └── DatapoolEventUpcasters.kt │ │ │ │ └── repository │ │ │ │ ├── FirstEventOnlyEventSourcingRepository.kt │ │ │ │ └── FirstEventOnlyEventSourcingRepositoryBuilder.kt │ │ │ └── test │ │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── polyflow │ │ │ │ └── datapool │ │ │ │ └── core │ │ │ │ ├── DataPoolCoreDeletionStrategyConfigurationTest.kt │ │ │ │ ├── business │ │ │ │ ├── DataEntryAggregateFirstEventOnlyEventSourcingRepositoryITest.kt │ │ │ │ ├── DataEntryAggregateTest.kt │ │ │ │ ├── repository │ │ │ │ │ └── FirstEventOnlyEventSourcingRepositoryBuilderTest.kt │ │ │ │ └── upcaster │ │ │ │ │ └── DataEntryCreatedEventUpcasterTest.kt │ │ │ │ └── itest │ │ │ │ └── TestApplication.kt │ │ │ └── resources │ │ │ ├── application-itest-first-event-only.yml │ │ │ ├── banner.txt │ │ │ ├── db │ │ │ └── migrations │ │ │ │ ├── V0_0_1__axon.sql │ │ │ │ ├── V0_0_2__axon_dlq.sql │ │ │ │ └── V0_0_3__axon_sequence_per_table.sql │ │ │ └── logback.xml │ ├── datapool-event │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── kotlin │ │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── camunda │ │ │ │ └── taskpool │ │ │ │ └── api │ │ │ │ └── business │ │ │ │ ├── BusinessEvents.kt │ │ │ │ └── Mappers.kt │ │ │ └── test │ │ │ └── kotlin │ │ │ └── io │ │ │ └── holunda │ │ │ └── camunda │ │ │ └── taskpool │ │ │ └── api │ │ │ └── business │ │ │ └── MappersTest.kt │ └── pom.xml ├── spring-utils │ ├── pom.xml │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── io │ │ │ └── holunda │ │ │ └── polyflow │ │ │ └── spring │ │ │ └── ApplicationNameBeanPostProcessor.kt │ │ └── test │ │ └── kotlin │ │ └── io │ │ └── holunda │ │ └── polyflow │ │ ├── datapool │ │ └── DataEntrySenderProperties.kt │ │ └── spring │ │ └── ApplicationNameBeanPostProcessorTest.kt └── taskpool │ ├── pom.xml │ ├── taskpool-api │ ├── pom.xml │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── io │ │ │ └── holunda │ │ │ └── camunda │ │ │ └── taskpool │ │ │ └── api │ │ │ ├── process │ │ │ ├── definition │ │ │ │ └── ProcessDefinitionCommand.kt │ │ │ ├── instance │ │ │ │ └── ProcessInstanceCommand.kt │ │ │ └── variable │ │ │ │ ├── ProcessVariableCommands.kt │ │ │ │ └── ProcessVariableValue.kt │ │ │ └── task │ │ │ ├── CamundaTaskEventType.kt │ │ │ ├── EngineTaskCommand.kt │ │ │ ├── EngineTaskCommandFilter.kt │ │ │ ├── EngineTaskCommandSorter.kt │ │ │ ├── EngineTaskCommands.kt │ │ │ ├── InteractionTaskCommand.kt │ │ │ ├── InteractionTaskCommands.kt │ │ │ ├── SourceReference.kt │ │ │ ├── TaskIdentity.kt │ │ │ ├── TaskIdentityWithPayloadAndCorrelations.kt │ │ │ ├── WithFormKey.kt │ │ │ ├── WithPayload.kt │ │ │ └── WithTaskId.kt │ │ └── test │ │ └── kotlin │ │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── taskpool │ │ └── sender │ │ └── CommandSorterTest.kt │ ├── taskpool-core │ ├── pom.xml │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── io │ │ │ └── holunda │ │ │ └── polyflow │ │ │ └── taskpool │ │ │ └── core │ │ │ ├── EnableTaskPool.kt │ │ │ ├── TaskPoolCoreConfiguration.kt │ │ │ ├── process │ │ │ ├── ProcessDefinitionAggregate.kt │ │ │ ├── ProcessDefinitionRegisterCommandHandler.kt │ │ │ ├── ProcessInstanceAggregate.kt │ │ │ └── ProcessInstanceVariablesChangeHandler.kt │ │ │ └── task │ │ │ ├── ExternalCommandHandler.kt │ │ │ ├── TaskAggregate.kt │ │ │ └── TaskAggregateEngineTaskCommandFilter.kt │ │ └── test │ │ ├── kotlin │ │ └── io │ │ │ └── holunda │ │ │ └── polyflow │ │ │ └── taskpool │ │ │ └── core │ │ │ ├── TestApplication.kt │ │ │ ├── process │ │ │ ├── ProcessDefinitionHandlerAggregateITest.kt │ │ │ ├── ProcessInstanceAggregateTest.kt │ │ │ └── ProcessInstanceVariableChangeAggregateITest.kt │ │ │ └── task │ │ │ ├── TaskAggregateClaimTest.kt │ │ │ ├── TaskAggregateDeferTest.kt │ │ │ ├── TaskAggregateEngineCommandTest.kt │ │ │ ├── TaskAssignmentChangeTest.kt │ │ │ ├── TaskAttributeUpdateTest.kt │ │ │ ├── TaskHandlerAggregateITest.kt │ │ │ └── TaskMarkToBeCompletedTest.kt │ │ └── resources │ │ ├── application-itest.yml │ │ ├── banner.txt │ │ ├── db │ │ └── migrations │ │ │ ├── V0_0_1__axon.sql │ │ │ ├── V0_0_2__axon_dlq.sql │ │ │ └── V0_0_3__axon_sequence_per_table.sql │ │ └── logback.xml │ └── taskpool-event │ ├── pom.xml │ └── src │ ├── main │ └── kotlin │ │ └── io │ │ └── holunda │ │ └── camunda │ │ └── taskpool │ │ ├── api │ │ ├── process │ │ │ ├── definition │ │ │ │ └── ProcessDefinitionEvents.kt │ │ │ ├── instance │ │ │ │ └── ProcessInstanceEvents.kt │ │ │ └── variable │ │ │ │ └── ProcessVariableEvents.kt │ │ └── task │ │ │ └── TaskEvents.kt │ │ ├── mapper │ │ ├── process │ │ │ ├── ProcessDefinitionMapper.kt │ │ │ └── ProcessInstanceMapper.kt │ │ └── task │ │ │ ├── TaskEventMappers.kt │ │ │ └── TaskFactoryMethods.kt │ │ ├── model │ │ └── Task.kt │ │ └── upcast │ │ ├── AnnotatedEventUpcaster.kt │ │ ├── AnnotationBasedSingleEventUpcaster.kt │ │ ├── RepresentationContentType.kt │ │ ├── TaskpoolEventUpcasters.kt │ │ ├── definition │ │ └── ProcessDefinitionEventUpcasters.kt │ │ └── task │ │ ├── TaskAttributeUpdatedEngineEvent4To5Upcaster.kt │ │ └── TaskEventEventUpcasterForPatchingSourceRefernce.kt │ └── test │ └── kotlin │ └── io │ └── holunda │ └── camunda │ └── taskpool │ └── upcast │ ├── ProcessDefinitionUpcasterTest.kt │ ├── TaskEventSourceReferenceUpcasterTest.kt │ └── TaskUpdateEventPayloadAndCorrelationUpcasterTest.kt ├── detekt.yml ├── docs ├── CNAME ├── assets │ └── img │ │ ├── bg.svg │ │ └── logo-negative.svg ├── developer-guide │ ├── contribution.md │ └── project-setup.md ├── examples │ ├── example-approval.md │ ├── example-components │ │ ├── index.md │ │ ├── pa-backend.md │ │ ├── pa-frontend.md │ │ ├── pp-backend.md │ │ ├── pp-frontend.md │ │ └── user-management.md │ ├── index.md │ └── scenarios │ │ ├── distributed-axon-server-local.md │ │ ├── distributed-axon-server.md │ │ ├── distributed-with-kafka.md │ │ ├── index.md │ │ └── single-node.md ├── getting-started │ └── index.md ├── img │ ├── Negative@2x.png │ ├── Positive@2x.png │ ├── api.graphml │ ├── architecture-collector.graphml │ ├── architecture-collector.png │ ├── collector-building-blocks.graphml │ ├── collector-building-blocks.png │ ├── deployment-axon-server-events-only.graphml │ ├── deployment-axon-server-events-only.png │ ├── deployment-axon-server.graphml │ ├── deployment-axon-server.png │ ├── deployment-messaging.graphml │ ├── deployment-messaging.png │ ├── deployment-single.graphml │ ├── deployment-single.png │ ├── example_amend_request.png │ ├── example_approve_request.png │ ├── example_archive_business_object.png │ ├── example_archive_completed.png │ ├── example_start_form.png │ ├── example_tasklist_approve_data.png │ ├── example_tasklist_approve_description.png │ ├── favicon.ico │ ├── favicon.png │ ├── polyflow-65x61.png │ ├── polyflow-hero-530x406.png │ ├── process-platform-architecture.graphml │ ├── process-platform-architecture.png │ ├── process_approve_request.png │ ├── scenario_kafka_messaging_overview.png │ ├── scenario_kafka_messaging_tx_view.png │ ├── scenario_kafka_to_tasklist_detail.png │ ├── scenario_process_application_to_kafka_detail.png │ ├── tasklist-angular-classic.png │ └── tasklist-angular-data.png ├── index.md ├── introduction │ ├── concepts.md │ ├── deployment.md │ ├── features.md │ ├── index.md │ └── solution-architecture.md ├── migration-guide │ └── index.md ├── reference-guide │ ├── components │ │ ├── camunda-interaction-client.md │ │ ├── camunda-starter.md │ │ ├── camunda-taskpool-collector.md │ │ ├── common-datapool-sender.md │ │ ├── common-taskpool-sender.md │ │ ├── core-datapool.md │ │ ├── core-taskpool.md │ │ ├── index.md │ │ ├── other-bus-jackson.md │ │ ├── other-tasklist-url-resolver.md │ │ ├── other-variable-serializer.md │ │ ├── view-api-client.md │ │ ├── view-api.md │ │ ├── view-form-url-resolver.md │ │ ├── view-jpa.md │ │ ├── view-mongo.md │ │ └── view-simple.md │ ├── configuration │ │ ├── core-datapool-aggregate-tuning.md │ │ ├── index.md │ │ ├── local-core-deployment.md │ │ ├── persistence.md │ │ └── view-mongo.md │ └── index.md ├── requirements.txt └── stylesheets │ └── extra.css ├── integration ├── camunda-bpm │ ├── engine-client │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ ├── kotlin │ │ │ │ └── io │ │ │ │ │ └── holunda │ │ │ │ │ └── polyflow │ │ │ │ │ └── client │ │ │ │ │ └── camunda │ │ │ │ │ ├── CamundaEngineClientAutoConfiguration.kt │ │ │ │ │ ├── CamundaEngineClientProperties.kt │ │ │ │ │ ├── EnableCamundaEngineClient.kt │ │ │ │ │ ├── process │ │ │ │ │ └── ProcessStarter.kt │ │ │ │ │ └── task │ │ │ │ │ └── TaskEventHandlers.kt │ │ │ └── resources │ │ │ │ └── META-INF │ │ │ │ └── spring │ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ │ └── test │ │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── polyflow │ │ │ │ └── client │ │ │ │ └── camunda │ │ │ │ ├── CamundaEngineClientPropertiesExtendedTest.kt │ │ │ │ ├── CamundaEngineClientPropertiesITest.kt │ │ │ │ ├── CamundaEngineClientPropertiesTestApplication.kt │ │ │ │ ├── process │ │ │ │ └── ProcessStarterTest.kt │ │ │ │ └── task │ │ │ │ └── TaskEventHandlerTest.kt │ │ │ └── resources │ │ │ ├── application-properties-itest.yaml │ │ │ ├── banner.txt │ │ │ └── logback.xml │ ├── pom.xml │ ├── springboot-autoconfigure │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── kotlin │ │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── polyflow │ │ │ │ └── taskpool │ │ │ │ ├── EnableTaskpoolEngineSupport.kt │ │ │ │ └── TaskpoolEngineSupportConfiguration.kt │ │ │ └── test │ │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── polyflow │ │ │ │ └── taskpool │ │ │ │ └── TaskpoolEngineSupportConfigurationITest.kt │ │ │ └── resources │ │ │ ├── application.yml │ │ │ ├── banner.txt │ │ │ └── logback.xml │ ├── springboot-starter │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── resources │ │ │ │ └── META-INF │ │ │ │ └── spring │ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ │ └── test │ │ │ ├── kotlin │ │ │ └── TaskpoolStarterITest.kt │ │ │ └── resources │ │ │ ├── application.yml │ │ │ └── banner.txt │ ├── taskpool-collector │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ ├── kotlin │ │ │ │ └── io │ │ │ │ │ └── holunda │ │ │ │ │ └── polyflow │ │ │ │ │ └── taskpool │ │ │ │ │ ├── CamundaEngineExtensions.kt │ │ │ │ │ ├── DelegateTaskExtensions.kt │ │ │ │ │ ├── EnableCamundaTaskpoolCollector.kt │ │ │ │ │ ├── HistoricProcessInstanceEventExtensions.kt │ │ │ │ │ ├── HistoricScopeInstanceEventExtensions.kt │ │ │ │ │ ├── HistoricVariableInstanceExtensions.kt │ │ │ │ │ ├── ProcessDefinitionEntityExtensions.kt │ │ │ │ │ ├── TaskEntityExtensions.kt │ │ │ │ │ ├── VariableMapExtensions.kt │ │ │ │ │ └── collector │ │ │ │ │ ├── CamundaTaskpoolCollectorConfiguration.kt │ │ │ │ │ ├── CamundaTaskpoolCollectorProperties.kt │ │ │ │ │ ├── FallbackProcessVariablesCorrelatorConfiguration.kt │ │ │ │ │ ├── FallbackProcessVariablesFilterConfiguration.kt │ │ │ │ │ ├── process │ │ │ │ │ ├── definition │ │ │ │ │ │ ├── ProcessDefinitionCollectorConfiguration.kt │ │ │ │ │ │ ├── ProcessDefinitionProcessor.kt │ │ │ │ │ │ ├── ProcessDefinitionService.kt │ │ │ │ │ │ ├── RefreshProcessDefinitionRegistrationParseListener.kt │ │ │ │ │ │ └── RefreshProcessDefinitionsEventingJobHandler.kt │ │ │ │ │ ├── instance │ │ │ │ │ │ ├── ProcessInstanceCollectorConfiguration.kt │ │ │ │ │ │ ├── ProcessInstanceEventCollectorService.kt │ │ │ │ │ │ └── ProcessInstanceProcessor.kt │ │ │ │ │ └── variable │ │ │ │ │ │ ├── ProcessVariableCollectorConfiguration.kt │ │ │ │ │ │ ├── ProcessVariableEventCollectorService.kt │ │ │ │ │ │ └── ProcessVariableProcessor.kt │ │ │ │ │ └── task │ │ │ │ │ ├── BuiltInPublishDelegateParseListener.kt │ │ │ │ │ ├── TaskAssigner.kt │ │ │ │ │ ├── TaskCollectorConfiguration.kt │ │ │ │ │ ├── TaskCommandProcessor.kt │ │ │ │ │ ├── TaskEventCollectorService.kt │ │ │ │ │ ├── TaskServiceCollectorService.kt │ │ │ │ │ ├── TaskVariableLoader.kt │ │ │ │ │ ├── VariablesEnricher.kt │ │ │ │ │ ├── assigner │ │ │ │ │ ├── EmptyTaskAssigner.kt │ │ │ │ │ ├── ProcessVariableChangeAssigningService.kt │ │ │ │ │ ├── ProcessVariableTaskAssignerMapping.kt │ │ │ │ │ └── ProcessVariablesTaskAssigner.kt │ │ │ │ │ └── enricher │ │ │ │ │ ├── EmptyTaskCommandEnricher.kt │ │ │ │ │ ├── ProcessVariableCorrelation.kt │ │ │ │ │ ├── ProcessVariableFilter.kt │ │ │ │ │ ├── ProcessVariablesCorrelator.kt │ │ │ │ │ ├── ProcessVariablesFilter.kt │ │ │ │ │ ├── ProcessVariablesTaskCommandEnricher.kt │ │ │ │ │ ├── ProcessVariablesTaskCommandEnricherFilter.kt │ │ │ │ │ └── VariableFilter.kt │ │ │ └── resources │ │ │ │ └── META-INF │ │ │ │ └── spring │ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ │ └── test │ │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── polyflow │ │ │ │ └── taskpool │ │ │ │ ├── collector │ │ │ │ ├── properties │ │ │ │ │ ├── CamundaTaskpoolCollectorPropertiesExtendedTest.kt │ │ │ │ │ └── CamundaTaskpoolCollectorPropertiesITest.kt │ │ │ │ └── task │ │ │ │ │ └── enricher │ │ │ │ │ ├── ProcessVariablesCorrelatorTest.kt │ │ │ │ │ └── ProcessVariablesFilterTest.kt │ │ │ │ └── itest │ │ │ │ ├── JacksonDataFormatConfigurator.kt │ │ │ │ ├── TestDriver.kt │ │ │ │ ├── tx │ │ │ │ ├── ProcessDefinitionServiceITest.kt │ │ │ │ └── TaskCollectorITest.kt │ │ │ │ └── txjob │ │ │ │ └── TaskTxJobSenderITest.kt │ │ │ └── resources │ │ │ ├── META-INF │ │ │ └── services │ │ │ │ └── org.camunda.spin.spi.DataFormatConfigurator │ │ │ ├── application-collector-tx-itest.yml │ │ │ ├── application-properties-itest.yml │ │ │ ├── application-txjob-sender-itest.yml │ │ │ ├── banner.txt │ │ │ ├── db │ │ │ └── migrations │ │ │ │ └── h2-postgresql │ │ │ │ ├── V0_0_1__postgres_engine_7.21.0.sql │ │ │ │ ├── V0_0_2__postgres_identity_7.21.0.sql │ │ │ │ └── V0_0_3__postgres_engine_7.21_to_7.22.sql │ │ │ ├── itest │ │ │ └── message_start_event.bpmn │ │ │ └── logback.xml │ └── taskpool-job-sender │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── polyflow │ │ │ │ └── taskpool │ │ │ │ └── sender │ │ │ │ ├── CamundaJobSenderConfiguration.kt │ │ │ │ ├── EngineTaskCommandsSendingJobHandler.kt │ │ │ │ ├── EngineTaskCommandsSendingJobHandlerConfiguration.kt │ │ │ │ └── TxAwareAccumulatingCamundaJobEngineTaskCommandSender.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── spring │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ └── test │ │ └── kotlin │ │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── taskpool │ │ └── sender │ │ ├── EngineTaskCommandsByteSerializationTest.kt │ │ ├── EngineTaskCommandsSendingJobHandlerConfigurationTest.kt │ │ └── TestObjectFactory.kt └── common │ ├── datapool-sender │ ├── pom.xml │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── io │ │ │ └── holunda │ │ │ └── polyflow │ │ │ └── datapool │ │ │ ├── DataEntrySenderConfiguration.kt │ │ │ ├── DataEntrySenderProperties.kt │ │ │ ├── DataEntrySenderType.kt │ │ │ ├── DataPoolSenderProperties.kt │ │ │ ├── EnableDataEntrySender.kt │ │ │ ├── projector │ │ │ ├── DataEntryProjectionSupplier.kt │ │ │ └── DataEntryProjector.kt │ │ │ └── sender │ │ │ ├── AbstractDataEntryCommandSender.kt │ │ │ ├── AbstractTxAwareAccumulatingDataEntryCommandSender.kt │ │ │ ├── DataEntryCommandSender.kt │ │ │ ├── DirectTxAwareAccumulatingDataEntryCommandSender.kt │ │ │ ├── SimpleDataEntryCommandSender.kt │ │ │ └── gateway │ │ │ ├── AxonCommandListGateway.kt │ │ │ ├── CommandListGateway.kt │ │ │ ├── LoggingDataEntryCommandErrorHandler.kt │ │ │ └── LoggingDataEntryCommandSuccessHandler.kt │ │ └── test │ │ ├── kotlin │ │ └── io │ │ │ └── holunda │ │ │ └── polyflow │ │ │ └── datapool │ │ │ ├── DataEntryDataPoolSenderPropertiesExtendedTest.kt │ │ │ ├── DataEntryDataPoolSenderPropertiesITest.kt │ │ │ └── PropertiesTestApplication.kt │ │ └── resources │ │ ├── application-properties-itest.yml │ │ ├── banner.txt │ │ └── logback.xml │ ├── pom.xml │ ├── tasklist-url-resolver │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── holunda │ │ │ │ └── polyflow │ │ │ │ └── urlresolver │ │ │ │ ├── FallbackTasklistUrlResolverAutoConfiguration.kt │ │ │ │ ├── TasklistUrlProperties.kt │ │ │ │ └── TasklistUrlResolver.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── spring │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ └── test │ │ ├── kotlin │ │ └── io │ │ │ └── holunda │ │ │ └── polyflow │ │ │ └── urlresolver │ │ │ ├── DataEntrySenderPropertiesExtendedTest.kt │ │ │ ├── DataEntrySenderPropertiesITest.kt │ │ │ └── PropertiesTestApplication.kt │ │ └── resources │ │ ├── banner.txt │ │ └── logback.xml │ ├── taskpool-sender │ ├── pom.xml │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── io │ │ │ └── holunda │ │ │ └── polyflow │ │ │ └── taskpool │ │ │ ├── EnableTaskpoolSender.kt │ │ │ ├── JacksonExtensions.kt │ │ │ ├── ProcessInstanceValueExtensions.kt │ │ │ └── sender │ │ │ ├── GenericTaskPublisher.kt │ │ │ ├── SenderConfiguration.kt │ │ │ ├── SenderProperties.kt │ │ │ ├── api │ │ │ └── Task.kt │ │ │ ├── gateway │ │ │ ├── AxonCommandListGateway.kt │ │ │ ├── CommandListGateway.kt │ │ │ ├── LoggingTaskCommandErrorHandler.kt │ │ │ └── LoggingTaskCommandSuccessHandler.kt │ │ │ ├── process │ │ │ ├── definition │ │ │ │ ├── ProcessDefinitionCommandSender.kt │ │ │ │ └── SimpleProcessDefinitionCommandSender.kt │ │ │ ├── instance │ │ │ │ ├── ProcessInstanceCommandSender.kt │ │ │ │ └── SimpleProcessInstanceCommandSender.kt │ │ │ └── variable │ │ │ │ ├── ProcessVariableCommandSender.kt │ │ │ │ ├── SimpleProcessVariableCommandSender.kt │ │ │ │ ├── SingleProcessVariableCommands.kt │ │ │ │ └── TxAwareAccumulatingProcessVariableCommandSender.kt │ │ │ └── task │ │ │ ├── AbstractTxAwareAccumulatingEngineTaskCommandSender.kt │ │ │ ├── DirectTxAwareAccumulatingEngineTaskCommandSender.kt │ │ │ ├── EngineTaskCommandSender.kt │ │ │ ├── SimpleEngineTaskCommandSender.kt │ │ │ └── accumulator │ │ │ ├── CommandAccumulator.kt │ │ │ ├── EngineTaskCommandIntentDetector.kt │ │ │ ├── EngineTaskCommandProjectionErrorDetector.kt │ │ │ ├── ProjectingCommandAccumulator.kt │ │ │ ├── SimpleEngineTaskCommandIntentDetector.kt │ │ │ ├── SortingCommandAccumulator.kt │ │ │ └── projectProperties.kt │ │ └── test │ │ ├── kotlin │ │ └── io │ │ │ └── holunda │ │ │ └── polyflow │ │ │ └── taskpool │ │ │ └── sender │ │ │ ├── PropertiesTestApplication.kt │ │ │ ├── SenderPropertiesExtendedTest.kt │ │ │ ├── SenderPropertiesITest.kt │ │ │ ├── gateway │ │ │ └── AxonCommandListGatewayTest.kt │ │ │ ├── process │ │ │ └── variable │ │ │ │ └── SimpleProcessVariableTest.kt │ │ │ └── task │ │ │ └── accumulator │ │ │ ├── CommandAccumulatorTest.kt │ │ │ ├── EngineTaskCommandIntentDetectorTest.kt │ │ │ └── ProjectPropertiesTest.kt │ │ └── resources │ │ ├── banner.txt │ │ └── logback.xml │ └── variable-serializer │ ├── pom.xml │ └── src │ ├── main │ └── kotlin │ │ ├── PathFilter.kt │ │ └── VariableSerializer.kt │ └── test │ └── kotlin │ ├── JsonPathWithValueTest.kt │ ├── TestFixtures.kt │ └── VariableSerializerTest.kt ├── mkdocs.yml ├── mvnw ├── mvnw.cmd ├── pom.xml └── view ├── form-url-resolver ├── pom.xml └── src │ ├── main │ └── kotlin │ │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── urlresolver │ │ ├── EnablePropertyBasedFormUrlResolver.kt │ │ ├── FormUrlResolverProperties.kt │ │ ├── PropertyBasedFormUrlResolver.kt │ │ └── PropertyBasedFormUrlResolverConfiguration.kt │ └── test │ ├── kotlin │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── urlresolver │ │ └── FormUrlResolverTest.kt │ └── resources │ └── form-url-properties.yml ├── jpa ├── pom.xml └── src │ ├── main │ └── kotlin │ │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── view │ │ └── jpa │ │ ├── CountByApplication.kt │ │ ├── EnablePolyflowJpaView.kt │ │ ├── JpaPolyflowViewDataEntryService.kt │ │ ├── JpaPolyflowViewProcessDefinitionService.kt │ │ ├── JpaPolyflowViewProcessInstanceService.kt │ │ ├── JpaPolyflowViewTaskService.kt │ │ ├── PolyflowJpaViewConfiguration.kt │ │ ├── PolyflowJpaViewProperties.kt │ │ ├── SpecificationExt.kt │ │ ├── auth │ │ ├── AuthorizationPrincipal.kt │ │ └── AuthorizationPrincipalType.kt │ │ ├── data │ │ ├── ConverterExt.kt │ │ ├── DataEntryEntity.kt │ │ ├── DataEntryEventHandler.kt │ │ ├── DataEntryId.kt │ │ ├── DataEntryPayloadAttributeEntity.kt │ │ ├── DataEntryPayloadAttributeEntityId.kt │ │ ├── DataEntryRepository.kt │ │ ├── DataEntryStateEmbeddable.kt │ │ └── ProtocolElement.kt │ │ ├── payload │ │ └── PayloadAttribute.kt │ │ ├── process │ │ ├── ConverterExt.kt │ │ ├── ProcessDefinitionEntity.kt │ │ ├── ProcessDefinitionRepository.kt │ │ ├── ProcessInstanceEntity.kt │ │ ├── ProcessInstanceRepository.kt │ │ └── SourceReferenceEmbeddable.kt │ │ ├── task │ │ ├── ConverterExt.kt │ │ ├── TaskAndDataEntryPayloadAttributeEntity.kt │ │ ├── TaskAndDataEntryPayloadAttributeEntityId.kt │ │ ├── TaskEntity.kt │ │ └── TaskRepository.kt │ │ └── update │ │ └── QueryEmitterExt.kt │ ├── sql │ └── persistence.xml │ └── test │ ├── kotlin │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── view │ │ └── jpa │ │ ├── JpaPolyflowViewServiceDataEntryCorrelationITest.kt │ │ ├── JpaPolyflowViewServiceDataEntryITest.kt │ │ ├── JpaPolyflowViewServiceDataEntryRevisionSupportITest.kt │ │ ├── JpaPolyflowViewServiceProcessDefinitionITest.kt │ │ ├── JpaPolyflowViewServiceProcessInstanceITest.kt │ │ ├── JpaPolyflowViewServiceTaskITest.kt │ │ ├── SpecificationTest.kt │ │ ├── TestFixtures.kt │ │ ├── auth │ │ └── AuthorizationPrincipalTest.kt │ │ ├── data │ │ ├── ConverterExtKtTest.kt │ │ ├── DataEntryIdTest.kt │ │ └── DataEntryRepositoryITest.kt │ │ ├── itest │ │ ├── FixedH2Dialect.kt │ │ ├── MockQueryEmitterConfiguration.kt │ │ ├── NoToastPostgresSQLDialect.kt │ │ ├── ObjectMapperConfiguration.kt │ │ ├── TestApplication.kt │ │ └── TestApplicationDataJpa.kt │ │ ├── process │ │ ├── ProcessDefinitionRepositoryITest.kt │ │ └── ProcessInstanceRepositoryITest.kt │ │ └── task │ │ ├── ConverterExtKtTest.kt │ │ ├── TaskEntityTest.kt │ │ └── TaskRepositoryITest.kt │ └── resources │ ├── application-itest-tc-mariadb.yaml │ ├── application-itest.yaml │ ├── banner.txt │ ├── db │ └── migrations │ │ ├── h2-postgresql │ │ ├── V0_0_10__axon_sequences_per_table.sql │ │ ├── V0_0_11__jpa_view_correlation_payload.sql │ │ ├── V0_0_12__jpa_plf_data_entry_correlations.sql │ │ ├── V0_0_1__postgres_engine_7.21.0.sql │ │ ├── V0_0_2__postgres_identity_7.21.0.sql │ │ ├── V0_0_3__admin.sql │ │ ├── V0_0_4__tasklist_filters.sql │ │ ├── V0_0_5__axon.sql │ │ ├── V0_0_6__request.sql │ │ ├── V0_0_7__jpa_view.sql │ │ ├── V0_0_8__axon_dlq.sql │ │ └── V0_0_9__polyflow_deleted.sql │ │ └── mariadb │ │ ├── V0_0_10__jpa_view_correlation_payload.sql │ │ ├── V0_0_11__jpa_plf_data_entry_correlations.sql │ │ ├── V0_0_1__mariadb_engine_7.21.0.sql │ │ ├── V0_0_2__mariadb_identity_7.21.0.sql │ │ ├── V0_0_3__admin.sql │ │ ├── V0_0_4__tasklist_filters.sql │ │ ├── V0_0_5__axon.sql │ │ ├── V0_0_6__request.sql │ │ ├── V0_0_7__jpa_view.sql │ │ ├── V0_0_8__axon_dlq.sql │ │ └── V0_0_9__axon_sequences_per_table.sql │ └── logback.xml ├── mongo ├── pom.xml └── src │ ├── main │ └── kotlin │ │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── view │ │ └── mongo │ │ ├── ChangeStreamOptionsSupport.kt │ │ ├── Converters.kt │ │ ├── EnableTaskPoolMongoView.kt │ │ ├── MongoViewService.kt │ │ ├── TaskPoolMongoViewConfiguration.kt │ │ ├── TaskPoolMongoViewProperties.kt │ │ ├── data │ │ ├── DataEntryChangeTracker.kt │ │ ├── DataEntryDocument.kt │ │ ├── DataEntryRepository.kt │ │ ├── DataEntryUpdateRepository.kt │ │ ├── DataEntryUpdateRepositoryImpl.kt │ │ └── ProtocolElement.kt │ │ ├── process │ │ ├── ProcessDefinitionDocument.kt │ │ ├── ProcessDefinitionMongoService.kt │ │ └── ProcessDefinitionRepository.kt │ │ ├── task │ │ ├── ReferenceDocument.kt │ │ ├── TaskChangeTracker.kt │ │ ├── TaskCountByApplicationRepositoryExtension.kt │ │ ├── TaskDocument.kt │ │ ├── TaskRepository.kt │ │ ├── TaskRepositoryExtension.kt │ │ ├── TaskRepositoryExtensionImpl.kt │ │ ├── TaskUpdatesExtension.kt │ │ ├── TaskWithDataEntriesDocument.kt │ │ ├── TaskWithDataEntriesRepository.kt │ │ ├── TaskWithDataEntriesRepositoryExtension.kt │ │ └── TaskWithDataEntriesRepositoryExtensionImpl.kt │ │ └── util │ │ └── CronTriggerWithJitter.kt │ └── test │ ├── kotlin │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── view │ │ └── mongo │ │ ├── TaskPoolMongoTestContext.kt │ │ ├── data │ │ └── DataEntryConverterTest.kt │ │ ├── service │ │ ├── PolyflowMongoServiceChangeStreamChangeTrackingITest.kt │ │ ├── PolyflowMongoServiceEventHandlerChangeTrackingITest.kt │ │ ├── PolyflowMongoServiceRetryTest.kt │ │ ├── PolyflowMongoServiceSortTest.kt │ │ ├── PolyflowMongoServiceTestBase.kt │ │ ├── PolyflowStages.kt │ │ └── TaskChangeTrackerTest.kt │ │ └── task │ │ ├── TaskDocumentBuilder.kt │ │ └── TaskRepositoryExtensionImplITest.kt │ └── resources │ ├── application-itest-replicated.yml │ ├── application-itest-standalone.yml │ ├── banner.txt │ └── logback.xml ├── pom.xml ├── simple ├── pom.xml └── src │ ├── main │ └── kotlin │ │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── view │ │ └── simple │ │ ├── EnablePolyflowSimpleView.kt │ │ ├── TaskPoolSimpleViewConfiguration.kt │ │ └── service │ │ ├── Converters.kt │ │ ├── RevisionSupport.kt │ │ ├── SimpleDataEntryService.kt │ │ ├── SimpleProcessDefinitionService.kt │ │ ├── SimpleProcessInstanceService.kt │ │ ├── SimpleProcessVariableService.kt │ │ ├── SimpleServiceViewProcessingGroup.kt │ │ └── SimpleTaskPoolService.kt │ └── test │ ├── kotlin │ └── io │ │ └── holunda │ │ └── polyflow │ │ └── view │ │ ├── TaskWithDataEntriesCorrelationTest.kt │ │ └── simple │ │ └── service │ │ ├── ConvertersKtTest.kt │ │ ├── DataPoolServiceTest.kt │ │ ├── DataPoolStages.kt │ │ ├── SimpleDataEntryServiceTest.kt │ │ ├── SimpleTaskPoolServicePerformanceTest.kt │ │ ├── SimpleTaskPoolServiceTest.kt │ │ ├── TaskPoolStages.kt │ │ ├── TestDataEntry.kt │ │ └── TestTaskData.kt │ └── resources │ └── logback.xml ├── view-api-client ├── pom.xml └── src │ └── main │ └── kotlin │ ├── DataEntryQueryClient.kt │ ├── ProcessDefinitionQueryClient.kt │ ├── ProcessInstanceQueryClient.kt │ ├── ProcessVariableQueryClient.kt │ ├── QueryGatewayExt.kt │ └── TaskQueryClient.kt └── view-api ├── pom.xml └── src ├── main └── kotlin │ ├── ComponentLike.kt │ ├── DataEntry.kt │ ├── Extensions.kt │ ├── FormUrlResolver.kt │ ├── ProcessDefinition.kt │ ├── ProcessInstance.kt │ ├── ProcessInstanceState.kt │ ├── ProcessVariable.kt │ ├── ProtocolEntry.kt │ ├── Task.kt │ ├── TaskWithDataEntries.kt │ ├── auth │ ├── User.kt │ └── UserService.kt │ ├── filter │ └── Filter.kt │ ├── query │ ├── FilterQuery.kt │ ├── PageableSortableQuery.kt │ ├── QueryResult.kt │ ├── data │ │ ├── DataEntriesForDataEntryTypeQuery.kt │ │ ├── DataEntriesForUserQuery.kt │ │ ├── DataEntriesQuery.kt │ │ ├── DataEntriesQueryResult.kt │ │ ├── DataEntryApi.kt │ │ ├── DataEntryForIdentityQuery.kt │ │ ├── QueryDataIdentity.kt │ │ └── ReactiveDataEntryApi.kt │ ├── process │ │ ├── ProcessDefinitionApi.kt │ │ ├── ProcessDefinitionsStartableByUserQuery.kt │ │ ├── ProcessInstanceApi.kt │ │ ├── ProcessInstanceQueryResult.kt │ │ ├── ProcessInstancesByStateQuery.kt │ │ ├── ReactiveProcessDefinitionApi.kt │ │ └── variable │ │ │ ├── ProcessVariableApi.kt │ │ │ ├── ProcessVariableFilter.kt │ │ │ ├── ProcessVariableQueryResult.kt │ │ │ ├── ProcessVariablesForInstanceQuery.kt │ │ │ └── filter │ │ │ ├── ProcessVariableFilterExactlyOne.kt │ │ │ └── ProcessVariableFilterOneOf.kt │ └── task │ │ ├── AllTasksQuery.kt │ │ ├── AllTasksWithDataEntriesQuery.kt │ │ ├── ApplicationWithTaskCount.kt │ │ ├── PageableSortableFilteredTaskQuery.kt │ │ ├── ReactiveTaskApi.kt │ │ ├── TaskApi.kt │ │ ├── TaskAttributeNamesQuery.kt │ │ ├── TaskAttributeNamesQueryResult.kt │ │ ├── TaskAttributeValuesQuery.kt │ │ ├── TaskAttributeValuesQueryResult.kt │ │ ├── TaskCountByApplicationQuery.kt │ │ ├── TaskForIdQuery.kt │ │ ├── TaskQueryResult.kt │ │ ├── TaskWithDataEntriesForIdQuery.kt │ │ ├── TasksForApplicationQuery.kt │ │ ├── TasksForCandidateUserAndGroupQuery.kt │ │ ├── TasksForGroupQuery.kt │ │ ├── TasksForUserQuery.kt │ │ ├── TasksWithDataEntriesForGroupQuery.kt │ │ ├── TasksWithDataEntriesForUserQuery.kt │ │ └── TasksWithDataEntriesQueryResult.kt │ └── sort │ ├── DataEntryComparator.kt │ ├── Sorter.kt │ ├── TaskComparator.kt │ └── TasksWithDataEntriesComparator.kt └── test └── kotlin ├── DataEntryTest.kt ├── ExtensionsTest.kt ├── TaskTest.kt ├── filter └── FilterTest.kt ├── query ├── PageableSortableQueryTest.kt ├── data │ ├── DataEntriesForUserQueryTest.kt │ ├── DataEntriesQueryTest.kt │ └── DataEntryForIdentityQueryTest.kt ├── process │ ├── ProcessDefinitionsStartableByUserQueryTest.kt │ └── ProcessInstanceByStateQueryTest.kt └── task │ ├── AllTasksQueryTest.kt │ ├── TaskForIdQueryTest.kt │ ├── TaskWithDataEntriesForGroupQueryTest.kt │ ├── TaskWithDataEntriesForIdQueryTest.kt │ ├── TaskWithDataEntriesForUserQueryTest.kt │ ├── TasksForApplicationQueryTest.kt │ ├── TasksForGroupQueryTest.kt │ └── TasksForUserQueryTest.kt └── sort └── ComparatorTest.kt /.codacy.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplications: 4 | exclude_paths: 5 | - "**/src/test/kotlin/**" 6 | exclude_paths: 7 | - "README.md" 8 | - ".github/**" 9 | - "docs/**" 10 | - "**.sql" 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | # We recommend you to keep these unchanged 9 | end_of_line = lf 10 | insert_final_newline = true 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | max_line_length = 160 14 | 15 | # camunda uses 2 spaces for indention 16 | indent_style = space 17 | indent_size = 2 18 | 19 | # in markdown, we might want trailing whitespaces 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please use one of the following templates: 2 | 3 | https://github.com/holunda-io/camunda-bpm-taskpool/issues/new/choose 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1_bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Bug report' 3 | about: 'Report a bug in camunda-bpm-taskpool' 4 | title: 5 | labels: 'type: bug :bug:' 6 | assignees: 7 | 8 | --- 9 | 10 | ### Steps to reproduce 11 | 12 | * camunda-bpm-taskpool version: 13 | * Camunda BPM version: 14 | * JDK version: 15 | * Operating system: 16 | * Complete executable reproducer: (e.g. GitHub Repo) 17 | * Steps: (what exactly are you doing with the above reproducer?) 18 | 19 | ### Expected behaviour 20 | 21 | ### Actual behaviour 22 | 23 | (In case of exceptions provide full stack trace) 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2_feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Feature request' 3 | about: 'Suggest a feature for camunda-bpm-taskpool' 4 | title: 5 | labels: 'type: enhancement' 6 | assignees: 7 | 8 | --- 9 | 10 | ### Scenario 11 | 12 | * camunda-bpm-taskpool version: 13 | * Camunda BPM version: 14 | * Description of your use case: (detailed description or executable reproducer, e.g. GitHub repo) 15 | 16 | ### Current Behaviour 17 | 18 | ### Wanted Behaviour 19 | 20 | ### Possible Workarounds 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | open-pull-requests-limit: 19 8 | labels: 9 | - "Type: dependencies" 10 | - package-ecosystem: "github-actions" 11 | directory: "/" 12 | schedule: 13 | interval: "daily" 14 | labels: 15 | - "Type: dependencies" 16 | -------------------------------------------------------------------------------- /.github/release-notes.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | sections: 3 | - title: ":rocket: Enhancements & Features" 4 | labels: [ "Type: enhancement", "Type: documentation", "Type: example" ] 5 | - title: ":zap: Breaking Changes" 6 | labels: [ "Type: breaking" ] 7 | - title: ":bug: Bug Fixes" 8 | labels: [ "Type: bug" ] 9 | - title: ":hammer_and_wrench: Chore" 10 | labels: [ "Type: dependencies" ] 11 | issues: 12 | exclude: 13 | labels: [ "Type: Incorrect Repository", "Type: question" ] 14 | contributors: 15 | exclude: 16 | names: [ "dependabot[bot]", "codacy-badger" ] 17 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip 2 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /core/bus-jackson/src/main/kotlin/io/holunda/polyflow/bus/jackson/DataEntryStateTypeMappingModule.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.bus.jackson 2 | 3 | import com.fasterxml.jackson.databind.module.SimpleModule 4 | import io.holunda.camunda.taskpool.api.business.DataEntryState 5 | import io.holunda.camunda.taskpool.api.business.DataEntryStateImpl 6 | 7 | /** 8 | * Module to map data entry state. 9 | */ 10 | class DataEntryStateTypeMappingModule: SimpleModule() { 11 | init { 12 | addAbstractTypeMapping(DataEntryState::class.java, DataEntryStateImpl::class.java) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/bus-jackson/src/main/kotlin/io/holunda/polyflow/bus/jackson/JsonAutoDetectAnyVisibility.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.bus.jackson 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect 4 | 5 | /** 6 | * Allow serialization of all fields. (Also private fields!) 7 | */ 8 | @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) 9 | class JsonAutoDetectAnyVisibility 10 | -------------------------------------------------------------------------------- /core/bus-jackson/src/main/kotlin/io/holunda/polyflow/bus/jackson/KotlinTypeInfo.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.bus.jackson 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeInfo 4 | 5 | /** 6 | * Type info for all classes using inheritance. 7 | */ 8 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class", include = JsonTypeInfo.As.PROPERTY) 9 | class KotlinTypeInfo 10 | -------------------------------------------------------------------------------- /core/bus-jackson/src/main/kotlin/io/holunda/polyflow/bus/jackson/VariableMapTypeMappingModule.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.bus.jackson 2 | 3 | import com.fasterxml.jackson.databind.module.SimpleModule 4 | import org.camunda.bpm.engine.variable.VariableMap 5 | import org.camunda.bpm.engine.variable.impl.VariableMapImpl 6 | 7 | /** 8 | * Module to map camunda variable impl. 9 | */ 10 | class VariableMapTypeMappingModule : SimpleModule() { 11 | init { 12 | addAbstractTypeMapping(VariableMap::class.java, VariableMapImpl::class.java) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/bus-jackson/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.holunda.polyflow.bus.jackson.config.FallbackPayloadObjectMapperAutoConfiguration 2 | -------------------------------------------------------------------------------- /core/datapool/datapool-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | io.holunda.polyflow 8 | polyflow-datapool-parent 9 | 4.4.1-SNAPSHOT 10 | 11 | 12 | polyflow-datapool-api 13 | core/datapool/${project.artifactId} 14 | 15 | 16 | 17 | org.axonframework 18 | axon-modelling 19 | 20 | 21 | org.camunda.commons 22 | camunda-commons-typed-values 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /core/datapool/datapool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/business/DataEntryState.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.business 2 | 3 | /** 4 | * Compound processing state. 5 | */ 6 | interface DataEntryState { 7 | /** 8 | * State type. 9 | */ 10 | val processingType: ProcessingType 11 | /** 12 | * Carrying business-relevant state label. 13 | */ 14 | val state: String? 15 | } 16 | 17 | /** 18 | * Simple implementation of compound entry state. 19 | */ 20 | data class DataEntryStateImpl( 21 | override val processingType: ProcessingType = ProcessingType.UNDEFINED, 22 | override val state: String = "" 23 | ) : DataEntryState 24 | -------------------------------------------------------------------------------- /core/datapool/datapool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/business/DataIdentity.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.business 2 | 3 | /** 4 | * Represents an identity of a data entry. 5 | */ 6 | interface DataIdentity { 7 | /** 8 | * String representation of an entry. 9 | */ 10 | val entryType: EntryType 11 | /** 12 | * String representation of an entry. 13 | */ 14 | val entryId: EntryId 15 | 16 | /** 17 | * Retrieves the identity as a string. 18 | */ 19 | fun asString() = dataIdentityString(entryType = entryType, entryId = entryId) 20 | } 21 | /** 22 | * Id of business entry. 23 | */ 24 | typealias EntryId = String 25 | 26 | /** 27 | * Type of business entry. 28 | */ 29 | typealias EntryType = String 30 | 31 | /** 32 | * Separator. 33 | */ 34 | const val DATA_IDENTITY_SEPARATOR = "#" 35 | 36 | /** 37 | * Constructs the data identity. 38 | */ 39 | fun dataIdentityString(entryType: EntryType, entryId: EntryId) = "$entryType$DATA_IDENTITY_SEPARATOR$entryId" 40 | -------------------------------------------------------------------------------- /core/datapool/datapool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/business/Modification.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.business 2 | 3 | import java.time.OffsetDateTime 4 | 5 | /** 6 | * Represents the auditable reason for data entry modification. 7 | */ 8 | data class Modification( 9 | /** 10 | * Time of update 11 | */ 12 | val time: OffsetDateTime = OffsetDateTime.now(), 13 | /** 14 | * Username of the user who updated the business entry. 15 | */ 16 | val username: String? = null, 17 | /** 18 | * Log entry for the update. 19 | */ 20 | val log: String? = null, 21 | 22 | /** 23 | * Log entry details. 24 | */ 25 | val logNotes: String? = null 26 | ) { 27 | companion object { 28 | /** 29 | * No modification null-object. 30 | */ 31 | val NONE = Modification() 32 | 33 | /** 34 | * Modification executed now. 35 | */ 36 | fun now() = Modification(time = OffsetDateTime.now()) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/datapool/datapool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/business/ProcessingType.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.business 2 | 3 | /** 4 | * State type of processing. 5 | */ 6 | enum class ProcessingType { 7 | /** 8 | * Before processing. 9 | */ 10 | PRELIMINARY, 11 | /** 12 | * During processing. 13 | */ 14 | IN_PROGRESS, 15 | /** 16 | * Process has finished the work on business entry with success. 17 | */ 18 | COMPLETED, 19 | /** 20 | * Process has failed to finish the work on business entry with success. 21 | */ 22 | CANCELLED, 23 | /** 24 | * Undefined status. 25 | */ 26 | UNDEFINED, 27 | /** 28 | * Data entry is deleted. 29 | */ 30 | DELETED; 31 | 32 | /** 33 | * Factory method. 34 | */ 35 | fun of(state: String = "") = DataEntryStateImpl(processingType = this, state = state) 36 | } 37 | -------------------------------------------------------------------------------- /core/datapool/datapool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/business/WithPayload.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.business 2 | 3 | import org.camunda.bpm.engine.variable.VariableMap 4 | 5 | /** 6 | * Represents data payload. 7 | */ 8 | interface WithPayload { 9 | /** 10 | * Payload. 11 | */ 12 | val payload: VariableMap 13 | } 14 | -------------------------------------------------------------------------------- /core/datapool/datapool-api/src/test/kotlin/io/holunda/camunda/taskpool/api/business/ProcessingTypeTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.business 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.junit.jupiter.api.Test 5 | 6 | internal class ProcessingTypeTest { 7 | 8 | @Test 9 | fun `creates processing type`() { 10 | assertThat(ProcessingType.PRELIMINARY.of("draft")).isEqualTo(DataEntryStateImpl(processingType = ProcessingType.PRELIMINARY, state = "draft")) 11 | assertThat(ProcessingType.IN_PROGRESS.of("doing")).isEqualTo(DataEntryStateImpl(processingType = ProcessingType.IN_PROGRESS, state = "doing")) 12 | assertThat(ProcessingType.COMPLETED.of("done")).isEqualTo(DataEntryStateImpl(processingType = ProcessingType.COMPLETED, state = "done")) 13 | assertThat(ProcessingType.DELETED.of("thrashed")).isEqualTo(DataEntryStateImpl(processingType = ProcessingType.DELETED, state = "thrashed")) 14 | assertThat(ProcessingType.CANCELLED.of("rejected")).isEqualTo(DataEntryStateImpl(processingType = ProcessingType.CANCELLED, state = "rejected")) 15 | assertThat(ProcessingType.UNDEFINED.of("custom")).isEqualTo(DataEntryStateImpl(processingType = ProcessingType.UNDEFINED, state = "custom")) 16 | } 17 | } -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/main/kotlin/io/holunda/polyflow/datapool/Helpers.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool 2 | 3 | import java.util.* 4 | 5 | /** 6 | * Allows to call a consumer if the element is present or call another callback, if the element is missing. 7 | * @param presentConsumer consumer the is called if the element is there. 8 | * @param missingCallback callback called if the element is missing. 9 | */ 10 | fun Optional.ifPresentOrElse(presentConsumer: (T) -> Unit, missingCallback: () -> Unit) { 11 | if (this.isPresent) { 12 | presentConsumer(this.get()) 13 | } else { 14 | missingCallback() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/main/kotlin/io/holunda/polyflow/datapool/core/DataPoolProperties.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.core 2 | 3 | import org.axonframework.eventsourcing.EventSourcingRepository 4 | import org.springframework.boot.context.properties.ConfigurationProperties 5 | 6 | /** 7 | * Properties effecting data pool command model. 8 | */ 9 | @ConfigurationProperties(prefix = "polyflow.core.data-entry") 10 | data class DataPoolProperties( 11 | /** 12 | * How many events lead to a snapshot of data entries. Check the [eventSourcingRepositoryType] property. 13 | */ 14 | val snapshotThreshold: Int = 5, 15 | 16 | /** 17 | * Specifies the full-qualified class name of the event sourced repository used to load data entry aggregates. 18 | * Defaults to [org.axonframework.eventsourcing.EventSourcingRepository]. 19 | * Consider to use [io.holunda.polyflow.datapool.core.repository.FirstEventOnlyEventSourcingRepository] if you want to load the aggregate with first event only. 20 | */ 21 | val eventSourcingRepositoryType: String = EventSourcingRepository::class.java.canonicalName, 22 | 23 | /** 24 | * Specifies the deletion strategy for data entries. 25 | */ 26 | val deletionStrategy: DeletionStrategyValue? = DeletionStrategyValue.lax 27 | ) 28 | -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/main/kotlin/io/holunda/polyflow/datapool/core/DeletionStrategy.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.core 2 | 3 | /** 4 | * Describes how deleted data entries should be handled. 5 | */ 6 | interface DeletionStrategy { 7 | /** 8 | * If set to true, the update event sent to the aggregate will result in AggregateDeletedException. 9 | * If set to false, the update of deleted data entry will undelete it and update the properties. 10 | */ 11 | fun strictMode(): Boolean 12 | } -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/main/kotlin/io/holunda/polyflow/datapool/core/DeletionStrategyValue.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.core 2 | 3 | /** 4 | * Different deletion strategies. 5 | */ 6 | enum class DeletionStrategyValue { 7 | /** 8 | * Allow updates after deletes. 9 | */ 10 | strict, 11 | 12 | /** 13 | * Enforces errors on any operation after deletion. 14 | */ 15 | lax 16 | } 17 | -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/main/kotlin/io/holunda/polyflow/datapool/core/EnablePolyflowDataPool.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.core 2 | 3 | import org.springframework.context.annotation.Import 4 | 5 | /** 6 | * Starts data pool component. 7 | */ 8 | @MustBeDocumented 9 | @Import( 10 | DataPoolCoreConfiguration::class, 11 | DataPoolCoreAxonConfiguration::class 12 | ) 13 | annotation class EnablePolyflowDataPool 14 | -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/test/kotlin/io/holunda/polyflow/datapool/core/business/repository/FirstEventOnlyEventSourcingRepositoryBuilderTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.core.business.repository 2 | 3 | import io.holunda.polyflow.datapool.core.business.DataEntryAggregate 4 | import io.holunda.polyflow.datapool.core.repository.FirstEventOnlyEventSourcingRepositoryBuilder 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.axonframework.eventsourcing.NoSnapshotTriggerDefinition 7 | import org.axonframework.eventsourcing.eventstore.EventStore 8 | import org.junit.jupiter.api.Test 9 | import org.mockito.kotlin.mock 10 | 11 | internal class FirstEventOnlyEventSourcingRepositoryBuilderTest { 12 | 13 | private val eventStore: EventStore = mock() 14 | 15 | @Test 16 | fun `should construct the builder with defaults`() { 17 | val builder = FirstEventOnlyEventSourcingRepositoryBuilder(DataEntryAggregate::class.java).eventStore(eventStore) 18 | 19 | assertThat(builder.internalEventStore()).isEqualTo(eventStore) 20 | assertThat(builder.internalSnapshotTriggerDefinition()).isEqualTo(NoSnapshotTriggerDefinition.INSTANCE) 21 | assertThat(builder.internalRepositoryProvider()).isNull() 22 | assertThat(builder.internalEventStreamFilter()).isNull() 23 | } 24 | } -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/test/kotlin/io/holunda/polyflow/datapool/core/itest/TestApplication.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.core.itest 2 | 3 | import com.thoughtworks.xstream.XStream 4 | import com.thoughtworks.xstream.security.AnyTypePermission 5 | import io.holunda.polyflow.datapool.core.EnablePolyflowDataPool 6 | import org.axonframework.eventsourcing.eventstore.inmemory.InMemoryEventStorageEngine 7 | import org.axonframework.serialization.Serializer 8 | import org.axonframework.serialization.xml.XStreamSerializer 9 | import org.springframework.beans.factory.annotation.Qualifier 10 | import org.springframework.boot.autoconfigure.SpringBootApplication 11 | import org.springframework.context.annotation.Bean 12 | 13 | @SpringBootApplication 14 | @EnablePolyflowDataPool 15 | class TestApplication { 16 | @Bean 17 | @Qualifier("eventSerializer") 18 | fun myEventSerializerForProcess(): Serializer = XStreamSerializer.builder().xStream(XStream().apply { addPermission(AnyTypePermission.ANY) }).build() 19 | 20 | @Bean 21 | fun inMemoryStorageEngine() = InMemoryEventStorageEngine() 22 | } 23 | -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/test/resources/application-itest-first-event-only.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: taskpool-core-itest 4 | datasource: 5 | url: jdbc:h2:mem:itest; 6 | username: sa 7 | password: 8 | jpa: 9 | generate-ddl: false 10 | hibernate.ddl-auto: validate 11 | show-sql: false 12 | open-in-view: false 13 | flyway: 14 | enabled: true 15 | locations: "classpath:db/migrations" 16 | 17 | polyflow: 18 | core: 19 | data-entry: 20 | event-sourcing-repository-type: io.holunda.polyflow.datapool.core.repository.FirstEventOnlyEventSourcingRepository 21 | 22 | logging.level: 23 | io.holunda.polyflow: 24 | datapool: 25 | core: 26 | business: 27 | DataEntryAggregate: DEBUG 28 | CreateOrUpdateCommandHandler: TRACE 29 | -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | I-Test Datapool Core 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/test/resources/db/migrations/V0_0_2__axon_dlq.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE dead_letter_entry ( 2 | dead_letter_id VARCHAR(255) NOT NULL, 3 | cause_message VARCHAR(255), 4 | cause_type VARCHAR(255), 5 | diagnostics BLOB, 6 | enqueued_at TIMESTAMP NOT NULL, 7 | last_touched TIMESTAMP, 8 | aggregate_identifier VARCHAR(255), 9 | event_identifier VARCHAR(255) NOT NULL, 10 | message_type VARCHAR(255) NOT NULL, 11 | meta_data BLOB, 12 | payload BLOB NOT NULL, 13 | payload_revision VARCHAR(255), 14 | payload_type VARCHAR(255) NOT NULL, 15 | sequence_number INT8, 16 | time_stamp VARCHAR(255) NOT NULL, 17 | token BLOB, 18 | token_type VARCHAR(255), 19 | type VARCHAR(255), 20 | processing_group VARCHAR(255) NOT NULL, 21 | processing_started TIMESTAMP, 22 | sequence_identifier VARCHAR(255) NOT NULL, 23 | sequence_index INT8 NOT NULL, 24 | PRIMARY KEY (dead_letter_id) 25 | ); -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/test/resources/db/migrations/V0_0_3__axon_sequence_per_table.sql: -------------------------------------------------------------------------------- 1 | drop SEQUENCE hibernate_sequence; 2 | create sequence association_value_entry_seq start with 1 increment by 50; 3 | create sequence domain_event_entry_seq start with 1 increment by 50; 4 | -------------------------------------------------------------------------------- /core/datapool/datapool-core/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /core/datapool/datapool-event/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | io.holunda.polyflow 8 | polyflow-datapool-parent 9 | 4.4.1-SNAPSHOT 10 | 11 | 12 | polyflow-datapool-event 13 | core/datapool/${project.artifactId} 14 | 15 | 16 | 17 | ${project.parent.groupId} 18 | polyflow-datapool-api 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /core/spring-utils/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | io.holunda.polyflow 8 | polyflow-parent 9 | 4.4.1-SNAPSHOT 10 | ../../bom/parent/pom.xml 11 | 12 | 13 | polyflow-spring-utils 14 | core/spring-utils/${project.artifactId} 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter 21 | provided 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-test 26 | test 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /core/spring-utils/src/test/kotlin/io/holunda/polyflow/datapool/DataEntrySenderProperties.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool 2 | 3 | import io.holunda.polyflow.spring.ApplicationNameBeanPostProcessor 4 | import org.springframework.boot.context.properties.ConfigurationProperties 5 | 6 | @ConfigurationProperties(prefix = "polyflow.test") 7 | data class DataEntrySenderProperties(var applicationName: String = ApplicationNameBeanPostProcessor.UNSET_APPLICATION_NAME) 8 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | io.holunda.polyflow 8 | polyflow-taskpool-parent 9 | 4.4.1-SNAPSHOT 10 | 11 | 12 | polyflow-taskpool-api 13 | core/taskpool/${project.artifactId} 14 | 15 | 16 | 17 | io.holunda.polyflow 18 | polyflow-datapool-api 19 | 20 | 21 | org.axonframework 22 | axon-messaging 23 | 24 | 25 | org.camunda.commons 26 | camunda-commons-typed-values 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/process/definition/ProcessDefinitionCommand.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.process.definition 2 | 3 | import io.holunda.camunda.taskpool.api.task.WithFormKey 4 | import org.axonframework.modelling.command.TargetAggregateIdentifier 5 | 6 | /** 7 | * Any command about process definition should implement this interface. 8 | */ 9 | interface ProcessDefinitionCommand { 10 | val processDefinitionId: String 11 | } 12 | 13 | /** 14 | * Informs about a process definition deployed in the engine. 15 | */ 16 | data class RegisterProcessDefinitionCommand( 17 | 18 | @TargetAggregateIdentifier 19 | override val processDefinitionId: String, 20 | val processDefinitionKey: String, 21 | val processDefinitionVersion: Int, 22 | 23 | val applicationName: String, 24 | val processName: String, 25 | val processVersionTag: String?, 26 | val processDescription: String?, 27 | override val formKey: String?, 28 | val startableFromTasklist: Boolean, 29 | val candidateStarterUsers: Set, 30 | val candidateStarterGroups: Set 31 | ) : ProcessDefinitionCommand, WithFormKey 32 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/CamundaTaskEventType.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | /** 4 | * Identifies camunda task event. 5 | */ 6 | interface CamundaTaskEventType { 7 | /** 8 | * Event classification. 9 | */ 10 | val eventName: String 11 | 12 | companion object { 13 | const val CREATE = "create" 14 | const val ASSIGN = "assignment" 15 | const val DELETE = "delete" 16 | const val COMPLETE = "complete" 17 | const val ATTRIBUTES = "attribute-update" 18 | const val ATTRIBUTES_LISTENER_UPDATE = "attribute-listener-update" 19 | const val CANDIDATE_GROUP_ADD = "candidate-group-add" 20 | const val CANDIDATE_GROUP_DELETE = "candidate-group-delete" 21 | const val CANDIDATE_USER_ADD = "candidate-user-add" 22 | const val CANDIDATE_USER_DELETE = "candidate-user-delete" 23 | const val BATCH = "batch" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/EngineTaskCommand.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | /** 4 | * Task command received from the Camunda Engine. 5 | */ 6 | interface EngineTaskCommand : WithTaskId, CamundaTaskEventType { 7 | /** 8 | * Used to order commands before sending in case multiple events are received from the engine for the same task in the same transaction. 9 | * Commands with lower order value are sent before commands with higher order value. 10 | */ 11 | val order: Int 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/EngineTaskCommandFilter.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | import java.util.function.Predicate 4 | 5 | /** 6 | * Filter for task commands. 7 | */ 8 | interface EngineTaskCommandFilter : Predicate { 9 | /** 10 | * Tests if the task command should be sent. 11 | * @param engineTaskCommand commend to test. 12 | * @return true, if command should be emitted. Defaults to false. 13 | */ 14 | override fun test(engineTaskCommand: EngineTaskCommand): Boolean = false 15 | } 16 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/EngineTaskCommandSorter.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | /** 4 | * Create can carry almost everything of changes. 5 | */ 6 | const val ORDER_TASK_CREATION = -3 7 | 8 | /** 9 | * Complete can carry assignee. 10 | */ 11 | const val ORDER_TASK_COMPLETION = -2 12 | const val ORDER_TASK_DELETION = -1 13 | const val ORDER_TASK_ASSIGNMENT = 0 14 | const val ORDER_TASK_CANDIDATES_UPDATE = 1 15 | const val ORDER_TASK_ATTRIBUTE_UPDATE = 2 16 | const val ORDER_TASK_BATCH = 100 17 | 18 | /** 19 | * Special command that is never an intent, but is used for enrichment of other commands. 20 | */ 21 | const val ORDER_TASK_HISTORIC_ATTRIBUTE_UPDATE = 10 22 | 23 | 24 | /** 25 | * Provides an ordering for EngineTaskCommand based on their order property. 26 | * This is used to determine the intent of the command batch. 27 | */ 28 | class EngineTaskCommandSorter : Comparator { 29 | 30 | override fun compare(command: EngineTaskCommand, otherCommand: EngineTaskCommand): Int { 31 | 32 | // EngineTaskCommand with lower order value comes first 33 | return command.order.compareTo(otherCommand.order) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/InteractionTaskCommand.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | /** 4 | * Task command caused by user or system interaction with a task. 5 | */ 6 | interface InteractionTaskCommand : TaskIdentity 7 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/TaskIdentity.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | /** 4 | * Task identity. 5 | */ 6 | interface TaskIdentity : WithTaskId { 7 | /** 8 | * Task definition key. 9 | */ 10 | val taskDefinitionKey: String 11 | /** 12 | * Task source reference. 13 | */ 14 | val sourceReference: SourceReference 15 | } 16 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/TaskIdentityWithPayloadAndCorrelations.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | import io.holunda.camunda.taskpool.api.business.WithCorrelations 4 | 5 | /** 6 | * Task identity which can be enriched with payload and correlations. 7 | */ 8 | interface TaskIdentityWithPayloadAndCorrelations : TaskIdentity, WithPayload, WithCorrelations { 9 | /** 10 | * Flag, indicating if the enrichment has been performed. The payload is only then taken into account. 11 | */ 12 | var enriched: Boolean 13 | } 14 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/WithFormKey.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | /** 4 | * Identifies elements with form key. 5 | */ 6 | interface WithFormKey { 7 | /** 8 | * Optional form key. 9 | */ 10 | val formKey: String? 11 | } 12 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/WithPayload.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | import org.camunda.bpm.engine.variable.VariableMap 4 | 5 | /** 6 | * Represents task payload. 7 | */ 8 | interface WithPayload { 9 | /** 10 | * Payload. 11 | */ 12 | val payload: VariableMap 13 | /** 14 | * Business key. 15 | */ 16 | val businessKey: String? 17 | } 18 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-api/src/main/kotlin/io/holunda/camunda/taskpool/api/task/WithTaskId.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.task 2 | 3 | /** 4 | * Identifies the fact that the task id is present. 5 | * This is a minimum requirement for the task to be identified. 6 | */ 7 | interface WithTaskId { 8 | /** 9 | * Task id. 10 | */ 11 | val id: String 12 | } 13 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/EnableTaskPool.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.core 2 | 3 | import org.springframework.context.annotation.Import 4 | 5 | /** 6 | * Starts task pool component. 7 | */ 8 | @MustBeDocumented 9 | @Import(TaskPoolCoreConfiguration::class) 10 | annotation class EnablePolyflowTaskPool 11 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/process/ProcessDefinitionRegisterCommandHandler.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.core.process 2 | 3 | import io.holunda.camunda.taskpool.api.process.definition.RegisterProcessDefinitionCommand 4 | import org.axonframework.commandhandling.CommandHandler 5 | import org.axonframework.eventsourcing.EventSourcingRepository 6 | import org.springframework.context.annotation.Lazy 7 | import org.springframework.stereotype.Component 8 | 9 | /** 10 | * Handler allowing to register existing definition multiple times. 11 | */ 12 | @Component 13 | class ProcessDefinitionRegisterCommandHandler( 14 | @Lazy 15 | val eventSourcingRepository: EventSourcingRepository 16 | ) { 17 | 18 | /** 19 | * Submits a register definition command to an existing aggregate or a new aggregate. 20 | */ 21 | @CommandHandler 22 | fun register(command: RegisterProcessDefinitionCommand) { 23 | eventSourcingRepository.loadOrCreate(command.processDefinitionId) { ProcessDefinitionAggregate() } 24 | .execute { it.handle(command) } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/process/ProcessInstanceVariablesChangeHandler.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.core.process 2 | 3 | import io.holunda.camunda.taskpool.api.process.variable.ChangeProcessVariablesForExecutionCommand 4 | import org.axonframework.commandhandling.CommandHandler 5 | import org.axonframework.eventsourcing.EventSourcingRepository 6 | import org.springframework.context.annotation.Lazy 7 | import org.springframework.stereotype.Component 8 | 9 | /** 10 | * This handler makes sure that an update of variables can be sent without a create of the process instance. 11 | */ 12 | @Component 13 | class ProcessInstanceVariablesChangeHandler( 14 | @Lazy 15 | val eventSourcingRepository: EventSourcingRepository 16 | ) { 17 | 18 | /** 19 | * Update variables on existing instance aggregate or create a new one, if missed. 20 | */ 21 | @CommandHandler 22 | fun update(command: ChangeProcessVariablesForExecutionCommand) { 23 | eventSourcingRepository.loadOrCreate(command.sourceReference.instanceId) { ProcessInstanceAggregate() } 24 | .execute { it.changeVariables(command) } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/main/kotlin/io/holunda/polyflow/taskpool/core/task/ExternalCommandHandler.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.core.task 2 | 3 | import io.holunda.camunda.taskpool.api.task.CreateTaskCommand 4 | import org.axonframework.commandhandling.CommandHandler 5 | import org.axonframework.eventsourcing.EventSourcingRepository 6 | import org.axonframework.messaging.MetaData 7 | import org.springframework.context.annotation.Lazy 8 | import org.springframework.stereotype.Component 9 | 10 | /** 11 | * Handler allowing to re-submit a create command for already existing task. 12 | */ 13 | @Component 14 | class ExternalCommandHandler( 15 | @Lazy 16 | val eventSourcingRepository: EventSourcingRepository 17 | ) { 18 | 19 | /** 20 | * Create a new aggregate (default) or load existing and replay the creation command if already there. 21 | */ 22 | @CommandHandler 23 | fun create(command: CreateTaskCommand, metadata: MetaData) { 24 | eventSourcingRepository.loadOrCreate(command.id) { TaskAggregate() } 25 | .execute { it.handle(command, metadata) } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/test/kotlin/io/holunda/polyflow/taskpool/core/TestApplication.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.core 2 | 3 | import com.thoughtworks.xstream.XStream 4 | import com.thoughtworks.xstream.security.AnyTypePermission 5 | import org.axonframework.eventsourcing.eventstore.inmemory.InMemoryEventStorageEngine 6 | import org.axonframework.serialization.Serializer 7 | import org.axonframework.serialization.xml.XStreamSerializer 8 | import org.springframework.beans.factory.annotation.Qualifier 9 | import org.springframework.boot.autoconfigure.SpringBootApplication 10 | import org.springframework.context.annotation.Bean 11 | 12 | @SpringBootApplication 13 | @EnablePolyflowTaskPool 14 | class TestApplication { 15 | @Bean 16 | @Qualifier("eventSerializer") 17 | fun myEventSerializerForProcess(): Serializer = XStreamSerializer.builder().xStream(XStream().apply { addPermission(AnyTypePermission.ANY) }).build() 18 | 19 | @Bean 20 | fun inMemoryEventStoreEngine() = InMemoryEventStorageEngine() 21 | } 22 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/test/resources/application-itest.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: taskpool-core-itest 4 | datasource: 5 | url: jdbc:h2:mem:itest; 6 | username: sa 7 | password: 8 | jpa: 9 | generate-ddl: false 10 | hibernate.ddl-auto: validate 11 | show-sql: false 12 | open-in-view: false 13 | flyway: 14 | enabled: true 15 | locations: "classpath:db/migrations" 16 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | I-Test Taskpool Core 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/test/resources/db/migrations/V0_0_2__axon_dlq.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE dead_letter_entry ( 2 | dead_letter_id VARCHAR(255) NOT NULL, 3 | cause_message VARCHAR(255), 4 | cause_type VARCHAR(255), 5 | diagnostics BLOB, 6 | enqueued_at TIMESTAMP NOT NULL, 7 | last_touched TIMESTAMP, 8 | aggregate_identifier VARCHAR(255), 9 | event_identifier VARCHAR(255) NOT NULL, 10 | message_type VARCHAR(255) NOT NULL, 11 | meta_data BLOB, 12 | payload BLOB NOT NULL, 13 | payload_revision VARCHAR(255), 14 | payload_type VARCHAR(255) NOT NULL, 15 | sequence_number INT8, 16 | time_stamp VARCHAR(255) NOT NULL, 17 | token BLOB, 18 | token_type VARCHAR(255), 19 | type VARCHAR(255), 20 | processing_group VARCHAR(255) NOT NULL, 21 | processing_started TIMESTAMP, 22 | sequence_identifier VARCHAR(255) NOT NULL, 23 | sequence_index INT8 NOT NULL, 24 | PRIMARY KEY (dead_letter_id) 25 | ); -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/test/resources/db/migrations/V0_0_3__axon_sequence_per_table.sql: -------------------------------------------------------------------------------- 1 | drop SEQUENCE hibernate_sequence; 2 | create sequence association_value_entry_seq start with 1 increment by 50; 3 | create sequence domain_event_entry_seq start with 1 increment by 50; 4 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-core/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-event/src/main/kotlin/io/holunda/camunda/taskpool/api/process/definition/ProcessDefinitionEvents.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.process.definition 2 | 3 | import org.axonframework.serialization.Revision 4 | 5 | /** 6 | * Event sent after a new process has been deployed. 7 | */ 8 | @Revision("1") 9 | data class ProcessDefinitionRegisteredEvent( 10 | val processDefinitionId: String, 11 | val processDefinitionKey: String, 12 | val processDefinitionVersion: Int, 13 | val applicationName: String, 14 | val processName: String, 15 | val processVersionTag: String?, 16 | val processDescription: String?, 17 | val formKey: String?, 18 | val startableFromTasklist: Boolean, 19 | val candidateStarterUsers: Set = setOf(), 20 | val candidateStarterGroups: Set = setOf() 21 | ) 22 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-event/src/main/kotlin/io/holunda/camunda/taskpool/api/process/variable/ProcessVariableEvents.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.api.process.variable 2 | 3 | import io.holunda.camunda.taskpool.api.task.SourceReference 4 | import org.axonframework.serialization.Revision 5 | 6 | /** 7 | * Variable has been changed. 8 | */ 9 | @Revision("1") 10 | data class ProcessVariablesChangedEvent( 11 | val sourceReference: SourceReference, 12 | val variableChanges: List 13 | ) 14 | -------------------------------------------------------------------------------- /core/taskpool/taskpool-event/src/main/kotlin/io/holunda/camunda/taskpool/mapper/process/ProcessDefinitionMapper.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.mapper.process 2 | 3 | import io.holunda.camunda.taskpool.api.process.definition.ProcessDefinitionRegisteredEvent 4 | import io.holunda.camunda.taskpool.api.process.definition.RegisterProcessDefinitionCommand 5 | 6 | /** 7 | * Maps command to event. 8 | */ 9 | fun RegisterProcessDefinitionCommand.registerEvent(): ProcessDefinitionRegisteredEvent = 10 | ProcessDefinitionRegisteredEvent( 11 | processDefinitionId = this.processDefinitionId, 12 | processDefinitionKey = this.processDefinitionKey, 13 | processDefinitionVersion = this.processDefinitionVersion, 14 | processDescription = this.processDescription, 15 | processName = this.processName, 16 | processVersionTag = this.processVersionTag, 17 | applicationName = this.applicationName, 18 | candidateStarterGroups = this.candidateStarterGroups, 19 | candidateStarterUsers = this.candidateStarterUsers, 20 | formKey = this.formKey, 21 | startableFromTasklist = this.startableFromTasklist 22 | ) -------------------------------------------------------------------------------- /core/taskpool/taskpool-event/src/main/kotlin/io/holunda/camunda/taskpool/upcast/AnnotatedEventUpcaster.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.upcast 2 | 3 | /** 4 | * Marks a single event upcaster. 5 | */ 6 | @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE) 7 | @MustBeDocumented 8 | annotation class AnnotatedEventUpcaster( 9 | /** 10 | * Target class type name. 11 | */ 12 | val targetClassTypeName: String, 13 | /** 14 | * Target revision, defaults to reserved value [NULL_VALUE] to indicate null. 15 | */ 16 | val revision: String = NULL_VALUE, 17 | 18 | /** 19 | * Representation content type. 20 | */ 21 | val representationContentType: RepresentationContentType = RepresentationContentType.XML 22 | ) { 23 | companion object { 24 | const val NULL_VALUE = "SINGLE_EVENT_UPCASTER_NULL_VALUE" 25 | } 26 | } -------------------------------------------------------------------------------- /core/taskpool/taskpool-event/src/main/kotlin/io/holunda/camunda/taskpool/upcast/RepresentationContentType.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.camunda.taskpool.upcast 2 | 3 | /** 4 | * Supported content types for this upcaster. 5 | */ 6 | enum class RepresentationContentType { 7 | JSON, XML 8 | } -------------------------------------------------------------------------------- /detekt.yml: -------------------------------------------------------------------------------- 1 | # 2 | # see https://github.com/arturbosch/detekt/blob/master/detekt-cli/src/main/resources/default-detekt-config.yml 3 | # 4 | comments: 5 | active: true 6 | excludes: [ "**/test/**","**/*Test.kt","*/src/test/kotlin/**/*.kt","**/*Stages.kt","**/*ITest.kt" ] 7 | CommentOverPrivateFunction: 8 | active: false 9 | CommentOverPrivateProperty: 10 | active: false 11 | EndOfSentenceFormat: 12 | active: false 13 | endOfSentenceFormat: ([.?!][ \t\n\r\f<])|([.?!:]$) 14 | UndocumentedPublicClass: 15 | active: true 16 | searchInNestedClass: true 17 | searchInInnerClass: true 18 | searchInInnerObject: true 19 | searchInInnerInterface: true 20 | UndocumentedPublicFunction: 21 | active: true 22 | 23 | performance: 24 | active: true 25 | SpreadOperator: 26 | active: false 27 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | www.holunda.io 2 | -------------------------------------------------------------------------------- /docs/developer-guide/contribution.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contribution 3 | --- 4 | 5 | There are several ways in which you may contribute to this project. 6 | 7 | * [File issues](https://github.com/holunda-io/camunda-bpm-taskpool/issues) 8 | * Submit a pull requests 9 | 10 | ## Found a bug or missing feature? 11 | 12 | Please [file an issue](https://github.com/holunda-io/camunda-bpm-taskpool/issues) in our 13 | issue tracking system. 14 | 15 | ## Submit a Pull Request 16 | 17 | If you found a solution to an [open issue](https://github.com/holunda-io/camunda-bpm-taskpool/issues) 18 | and implemented it, we would be happy to add your contribution in the code base. For doing so, 19 | please create a pull request. Prior to that, please make sure you: 20 | 21 | - rebase against the `develop` branch 22 | - stick to project coding conventions 23 | - added test cases for the problem you are solving 24 | - added docs, describing the change 25 | - generally comply with codacy report 26 | -------------------------------------------------------------------------------- /docs/examples/example-components/pa-backend.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Process Application Backend 4 | --- 5 | 6 | The process application backend is implementing the process described in the [Example application](../example-application/). 7 | It demonstrates a typical three-tier application, following the Boundary-Control-Entity pattern. 8 | 9 | ## Boundary Tier 10 | The REST API is defined using OpenAPI specification and is implemented by Spring MVC controllers. It defines of four 11 | logical parts: 12 | 13 | - Environment Controller 14 | - Request Controller 15 | - Approve Task Controller 16 | - Amend Task Controller 17 | 18 | ## Control Tier 19 | The control tier is implemented using stateless Spring Beans and orchestrated by the Camunda BPM Process. 20 | Typical `JavaDelegate` and `ExecutionListener` are used as a glue layer. Business services of this layer are 21 | responsible for the integration with `Datapool Components` to reflect the status of the `Request` business entity. 22 | The Camunda BPM Engine is configured to use the `TaskCollector` to integrate with remaining components of 23 | the `camunda-bpm-taskpool`. 24 | 25 | ## Entity Tier 26 | The entity tier is implemented using Spring Data JPA, using Hibernate entities. Application data and process engine data is stored using a RDBMS. 27 | -------------------------------------------------------------------------------- /docs/examples/example-components/pa-frontend.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Process Application Frontend 4 | --- 5 | 6 | The process application frontend is implementing the user task forms and business object views for the 7 | example application. It is built as a typical Angular Single Page Application (SPA) and provides 8 | views for both user tasks and the business objects. It communicates with process application backend via 9 | REST API, defined in the latter. 10 | 11 | The user primarily interacts with the process platform which seamlessly integrates with the process applications. 12 | Usually, it provides integration points for user-task embedding / UI-composition. Unfortunately, 13 | this topic strongly depends on the frontend technology and is not a subject we want to demonstrate 14 | in this example. For simplicity, we built a very simple example, skipping the UI composition / integration entirely. 15 | 16 | The navigation between the process platform and process application is just as simple as a full page 17 | navigation of a hyperlink. 18 | -------------------------------------------------------------------------------- /docs/examples/example-components/pp-backend.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Process Platform Backend 4 | --- 5 | 6 | The purpose of the example process platform backend is to demonstrate how __process agnostic__ parts of the 7 | process solution can be implemented. 8 | -------------------------------------------------------------------------------- /docs/examples/example-components/user-management.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: User Management 4 | --- 5 | 6 | Usually, a central user management like a Single-Sign-On (SSO) is a part deployed into the process application 7 | landscape. This is responsible for authentication and authorization of the user and is required to control the 8 | role-based access to user tasks. 9 | 10 | In our example application, we __disable any security checks__ to avoid the unneeded complexity. In doing so, we 11 | implemented a trivial user store holding some pre-defined users used in example components and allow to simply 12 | switch users from the frontend by choosing a different user from the drop-down list. 13 | 14 | It is integrated with the example frontends by passing around the user id along with the requests and provide a way 15 | to resolve the user by that id. Technically speaking, the user id can be used to retrieve the permissions of the user 16 | and check them in the backend. 17 | -------------------------------------------------------------------------------- /docs/examples/index.md: -------------------------------------------------------------------------------- 1 | We provide the following examples to demonstrate the features of Polyflow: 2 | 3 | - [Example Approval](example-approval.md) -------------------------------------------------------------------------------- /docs/examples/scenarios/single-node.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Scenario for running on a single node 3 | --- 4 | 5 | This example demonstrates the usage of the Camunda BPM Taskpool deployed in one single node and is built as a SpringBoot application 6 | described in the [Deployment](../../introduction/deployment.md) section. 7 | 8 | ### System Requirements 9 | 10 | * JDK 11 11 | 12 | ### Preparations 13 | 14 | Before you begin, please build the entire project with `./mvnw clean install` from the command line in the project root directory. 15 | 16 | ### Start 17 | 18 | The demo application consists of one Maven module which can be started by running from command line in 19 | the `examples/scenarios/single-node-jpa` directory using Maven. Alternatively you can start the packaged application using: 20 | 21 | ```bash 22 | java -jar target/*.jar 23 | ``` 24 | 25 | ## Useful URLs 26 | 27 | * [http://localhost:8080/polyflow/](http://localhost:8080/polyflow/) 28 | * [http://localhost:8080/swagger-ui/](http://localhost:8080/swagger-ui/) 29 | * [http://localhost:8080/camunda/app/tasklist/default/](http://localhost:8080/camunda/app/tasklist/default/) 30 | -------------------------------------------------------------------------------- /docs/img/Negative@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/Negative@2x.png -------------------------------------------------------------------------------- /docs/img/Positive@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/Positive@2x.png -------------------------------------------------------------------------------- /docs/img/architecture-collector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/architecture-collector.png -------------------------------------------------------------------------------- /docs/img/collector-building-blocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/collector-building-blocks.png -------------------------------------------------------------------------------- /docs/img/deployment-axon-server-events-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/deployment-axon-server-events-only.png -------------------------------------------------------------------------------- /docs/img/deployment-axon-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/deployment-axon-server.png -------------------------------------------------------------------------------- /docs/img/deployment-messaging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/deployment-messaging.png -------------------------------------------------------------------------------- /docs/img/deployment-single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/deployment-single.png -------------------------------------------------------------------------------- /docs/img/example_amend_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/example_amend_request.png -------------------------------------------------------------------------------- /docs/img/example_approve_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/example_approve_request.png -------------------------------------------------------------------------------- /docs/img/example_archive_business_object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/example_archive_business_object.png -------------------------------------------------------------------------------- /docs/img/example_archive_completed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/example_archive_completed.png -------------------------------------------------------------------------------- /docs/img/example_start_form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/example_start_form.png -------------------------------------------------------------------------------- /docs/img/example_tasklist_approve_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/example_tasklist_approve_data.png -------------------------------------------------------------------------------- /docs/img/example_tasklist_approve_description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/example_tasklist_approve_description.png -------------------------------------------------------------------------------- /docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/favicon.ico -------------------------------------------------------------------------------- /docs/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/favicon.png -------------------------------------------------------------------------------- /docs/img/polyflow-65x61.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/polyflow-65x61.png -------------------------------------------------------------------------------- /docs/img/polyflow-hero-530x406.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/polyflow-hero-530x406.png -------------------------------------------------------------------------------- /docs/img/process-platform-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/process-platform-architecture.png -------------------------------------------------------------------------------- /docs/img/process_approve_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/process_approve_request.png -------------------------------------------------------------------------------- /docs/img/scenario_kafka_messaging_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/scenario_kafka_messaging_overview.png -------------------------------------------------------------------------------- /docs/img/scenario_kafka_messaging_tx_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/scenario_kafka_messaging_tx_view.png -------------------------------------------------------------------------------- /docs/img/scenario_kafka_to_tasklist_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/scenario_kafka_to_tasklist_detail.png -------------------------------------------------------------------------------- /docs/img/scenario_process_application_to_kafka_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/scenario_process_application_to_kafka_detail.png -------------------------------------------------------------------------------- /docs/img/tasklist-angular-classic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/tasklist-angular-classic.png -------------------------------------------------------------------------------- /docs/img/tasklist-angular-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holunda-io/camunda-bpm-taskpool/01eff184afcf3b1de13483a2172ddfae69c88438/docs/img/tasklist-angular-data.png -------------------------------------------------------------------------------- /docs/migration-guide/index.md: -------------------------------------------------------------------------------- 1 | This guide contains hints for upgrading to newer versions whenever there are breaking changes. 2 | 3 | ## Migrating to 4.x 4 | 5 | Version 4.x upgrades the Spring Boot dependency from 2.x to 3.x, which also requires upgrading Camunda to >=7.20 and Axon to >=4.7. It also means that Hibernate 6 is used now, 6 | which changes the way database sequences are created for sequence generators. 7 | 8 | Axon uses sequence generators for its tables and thus if you come from an older Hibernate version, you probably have a sequence called `hibernate_sequence` in your database. 9 | You can either create separate sequences per table and take care to have them start at the right value (recommended in 10 | the [Axon migration guide](https://docs.axoniq.io/reference-guide/axon-framework/upgrading-to-4-7#step-3-1)) or set the JPA property `hibernate.id.db_structure_naming_strategy` 11 | to `legacy` to restore the old behavior. In the Spring application properties, you would have to set this property: 12 | 13 | ```properties 14 | spring.jpa.properties.hibernate.id.db_structure_naming_strategy=legacy 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/reference-guide/components/camunda-interaction-client.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Camunda Engine Interaction Client 3 | pageId: engine-interaction-client 4 | --- 5 | 6 | ## Camunda Engine Interaction Client 7 | 8 | 9 | ### Purpose 10 | 11 | This component performs changes delivered by Camunda Interaction Events on Camunda BPM engine. 12 | The following Camunda Interaction Events are supported: 13 | 14 | * Claim User Task 15 | * Unclaim User Task 16 | * Defer User Task 17 | * Undefer User Task 18 | * Complete User Task 19 | 20 | ### Usage and configuration 21 | 22 | To use Camunda Engine Interaction Client please add the following artifact to your classpath: 23 | 24 | ```xml 25 | 26 | io.holunda.polyflow 27 | polyflow-camunda-bpm-engine-client 28 | 29 | ``` 30 | 31 | In your `application.yml` configure the application name of your process engine, to receive commands: 32 | 33 | ```yml 34 | polyflow: 35 | integration: 36 | client: 37 | camunda: 38 | application-name: my-process-application # defaults to ${spring.application.name} 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/reference-guide/components/camunda-starter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Camunda Engine Taskpool Support SpringBoot Starter 3 | pageId: engine-starter 4 | --- 5 | 6 | ### Purpose 7 | 8 | The Polyflow Camunda Platform 7 SpringBoot Starter is a convenience module providing a single 9 | module dependency to be included in the process application. It includes all process application 10 | modules and provides meaningful defaults for their options. 11 | 12 | ### Configuration 13 | 14 | In order to enable the starter, please put the following dependency on your class path: 15 | 16 | ```xml 17 | 18 | io.holunda.polyflow 19 | polyflow-camunda-bpm-springboot-starter 20 | 21 | ``` 22 | 23 | The included `TaskpoolEngineSupportConfiguration` is a SpringBoot AutoConfiguration that configures the required components. 24 | If you want to configure it manually, please add the `@EnableTaskpoolEngineSupport` annotation on any `@Configuration` annotated 25 | class of your SpringBoot application. 26 | 27 | The `@EnableTaskpoolEngineSupport` annotation has the same effect as the following block of annotations: 28 | 29 | ```java 30 | @EnableCamundaTaskpoolCollector 31 | @EnableDataEntrySender 32 | public class MyApplication { 33 | //... 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/reference-guide/components/core-taskpool.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Taskpool Core 4 | pageId: core-taskpool 5 | 6 | --- 7 | ### Purpose 8 | 9 | The component is responsible for maintaining and storing the consistent state of the taskpool 10 | core concepts: 11 | 12 | * Task (represents a user task instance) 13 | * Process Definition (represents a process definition) 14 | 15 | The component receives all commands and emits events, if changes are performed on underlying entities. 16 | The event stream is used to store all changes (purely event-sourced) and should be used by all other 17 | parties interested in changes. 18 | -------------------------------------------------------------------------------- /docs/reference-guide/components/other-variable-serializer.md: -------------------------------------------------------------------------------- 1 | ### Purpose 2 | 3 | Provides shared code configuring the variable serializer. 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/reference-guide/components/view-api-client.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | The Polyflow View API Client is a client for the users of the task-pool and the data-pool query API. It provides simple components which can be used 4 | in order to query the configured views. By doing so, it defines an easy-to-use API for **callers**. 5 | 6 | ## Usage 7 | 8 | Please put the following component to you class path: 9 | 10 | ```xml 11 | 12 | io.holunda.polyflow 13 | polyflow-view-api-client 14 | 15 | ``` 16 | 17 | The components available are: 18 | 19 | * `io.holunda.polyflow.view.DataEntryQueryClient` 20 | * `io.holunda.polyflow.view.ProcessDefinitionQueryClient` 21 | * `io.holunda.polyflow.view.ProcessInstanceQueryClient` 22 | * `io.holunda.polyflow.view.ProcessVariableQueryClient` 23 | * `io.holunda.polyflow.view.TaskQueryClient` 24 | 25 | To initialize the client, you need to pass the `queryGateway` to it: 26 | 27 | ```kotlin 28 | @Bean 29 | fun myTaskClient(queryGateway: QueryGateway) = TaskQueryClient(queryGateway) 30 | 31 | ``` 32 | 33 | If you are using Kotlin, you might like the extension functions of the `QueryGateway` provided by `io.holunda.polyflow.view.QueryGatewayExt` object. 34 | -------------------------------------------------------------------------------- /docs/reference-guide/configuration/index.md: -------------------------------------------------------------------------------- 1 | This is a root of configuration reference guide. 2 | 3 | Here are some dedicated articles: 4 | 5 | * [Persistence configuration](persistence.md) 6 | * [Mongo DB View configuration](view-mongo.md) 7 | * [Datapool Aggregate Tuning](core-datapool-aggregate-tuning.md) 8 | * [Deployment of Polyflow Core inside Process applications](local-core-deployment.md) 9 | -------------------------------------------------------------------------------- /docs/reference-guide/configuration/persistence.md: -------------------------------------------------------------------------------- 1 | ## Persistence 2 | 3 | If you use relational databases for your Event Store of the [DataPool](../components/core-datapool.md) or [TaskPool](../components/core-taskpool.md) or your view, 4 | using the [JPA View](../components/view-jpa.md), Axon Framework, used as a component of Polyflow will detect and autoconfigure itself. Especially, if you use 5 | Spring Data JPA or Spring JDBC, Axon auto-configuration will try to reuse it. 6 | 7 | If you are using `@EntityScan` annotation, you need to add Axon entities to the scan. To do so, please the following code on top of a class marked with `@Configuration`. 8 | 9 | ```kotlin 10 | @Configuration 11 | @EntityScan( 12 | basePackageClasses = [ 13 | TokenEntry::class, DomainEventEntry::class, SagaEntry::class 14 | ] 15 | ) 16 | class MyConfiguration 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/reference-guide/index.md: -------------------------------------------------------------------------------- 1 | This reference guide is a primary source of information in order to understand how Polyflow components are used and how to configure them. 2 | It is divided into tow major sections: 3 | 4 | * [Components](components) 5 | * [Configuration](configuration) 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs 2 | mkdocs-git-committers-plugin 3 | mkdocs-material 4 | mike 5 | mkdocs-git-revision-date-localized-plugin 6 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/main/kotlin/io/holunda/polyflow/client/camunda/CamundaEngineClientAutoConfiguration.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.client.camunda 2 | 3 | import io.holunda.polyflow.spring.ApplicationNameBeanPostProcessor 4 | import org.camunda.bpm.spring.boot.starter.CamundaBpmAutoConfiguration 5 | import org.springframework.boot.autoconfigure.AutoConfigureAfter 6 | import org.springframework.boot.context.properties.EnableConfigurationProperties 7 | import org.springframework.context.annotation.ComponentScan 8 | import org.springframework.context.annotation.Import 9 | 10 | /** 11 | * Engine client configuration enabling the event handling of interaction commands. 12 | */ 13 | @ComponentScan 14 | @AutoConfigureAfter(CamundaBpmAutoConfiguration::class) 15 | @EnableConfigurationProperties(CamundaEngineClientProperties::class) 16 | @Import(ApplicationNameBeanPostProcessor::class) 17 | class CamundaEngineClientAutoConfiguration 18 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/main/kotlin/io/holunda/polyflow/client/camunda/CamundaEngineClientProperties.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.client.camunda 2 | 3 | import io.holunda.polyflow.spring.ApplicationNameBeanPostProcessor.Companion.UNSET_APPLICATION_NAME 4 | import org.springframework.boot.context.properties.ConfigurationProperties 5 | 6 | /** 7 | * Properties to configure Camunda to receive interaction commands via Axon. 8 | */ 9 | @ConfigurationProperties("polyflow.integration.client.camunda") 10 | data class CamundaEngineClientProperties( 11 | 12 | /** 13 | * Denotes the (logical) name of the process application. 14 | * As Default, spring.application.name will be used 15 | */ 16 | // The default is set by ApplicationNameBeanPostProcessor 17 | var applicationName: String = UNSET_APPLICATION_NAME 18 | ) 19 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/main/kotlin/io/holunda/polyflow/client/camunda/EnableCamundaEngineClient.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.client.camunda 2 | 3 | import org.springframework.context.annotation.Import 4 | 5 | /** 6 | * Starts camunda client component accepting interaction commands. 7 | */ 8 | @MustBeDocumented 9 | @Import(CamundaEngineClientAutoConfiguration::class) 10 | annotation class EnableCamundaEngineClient 11 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/main/kotlin/io/holunda/polyflow/client/camunda/process/ProcessStarter.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.client.camunda.process 2 | 3 | import org.camunda.bpm.engine.RuntimeService 4 | import org.camunda.bpm.engine.variable.VariableMap 5 | import org.springframework.stereotype.Component 6 | 7 | /** 8 | * Starts process. 9 | */ 10 | @Component 11 | class ProcessStarter(private val runtimeService: RuntimeService) { 12 | 13 | /** 14 | * Starts process. 15 | * @param processDefinitionKey definition key. 16 | * @param payload variables. 17 | * @param businessKey optional business key. 18 | * @return process instance id. 19 | */ 20 | fun startProcess( 21 | processDefinitionKey: String, 22 | payload: VariableMap, 23 | businessKey: String? 24 | ): String { 25 | val instance = if (businessKey != null) { 26 | runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, payload) 27 | } else { 28 | runtimeService.startProcessInstanceByKey(processDefinitionKey, payload) 29 | } 30 | return instance.processInstanceId 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.holunda.polyflow.client.camunda.CamundaEngineClientAutoConfiguration 2 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/test/kotlin/io/holunda/polyflow/client/camunda/CamundaEngineClientPropertiesITest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.client.camunda 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.camunda.bpm.engine.RuntimeService 5 | import org.camunda.bpm.engine.TaskService 6 | import org.junit.jupiter.api.Test 7 | import org.springframework.beans.factory.annotation.Autowired 8 | import org.springframework.boot.test.context.SpringBootTest 9 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment.MOCK 10 | import org.springframework.boot.test.mock.mockito.MockBean 11 | import org.springframework.test.context.ActiveProfiles 12 | 13 | @SpringBootTest(classes = [CamundaEngineClientPropertiesTestApplication::class], webEnvironment = MOCK) 14 | @ActiveProfiles("properties-itest") 15 | class CamundaEngineClientPropertiesITest { 16 | 17 | @MockBean 18 | lateinit var runtimeService: RuntimeService 19 | 20 | @MockBean 21 | lateinit var taskService: TaskService 22 | 23 | @Autowired 24 | lateinit var props: CamundaEngineClientProperties 25 | 26 | @Test 27 | fun test_properties() { 28 | assertThat(props.applicationName).isEqualTo("Foo") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/test/kotlin/io/holunda/polyflow/client/camunda/CamundaEngineClientPropertiesTestApplication.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.client.camunda 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties 5 | 6 | @SpringBootApplication 7 | @EnableConfigurationProperties(CamundaEngineClientProperties::class) 8 | class CamundaEngineClientPropertiesTestApplication 9 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/test/resources/application-properties-itest.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: Foo 4 | 5 | axon: 6 | axonserver: 7 | enabled: false 8 | 9 | camunda: 10 | bpm: 11 | enabled: false 12 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | I-Test using SpringBoot: ${spring-boot.version}, Camunda ${camunda.bpm.version} 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /integration/camunda-bpm/engine-client/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /integration/camunda-bpm/springboot-autoconfigure/src/main/kotlin/io/holunda/polyflow/taskpool/EnableTaskpoolEngineSupport.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool 2 | 3 | import org.springframework.context.annotation.Import 4 | 5 | /** 6 | * Put this annotation on your process application configuration to enable 7 | * defaults of task pool engine components. 8 | */ 9 | @MustBeDocumented 10 | @Import(TaskpoolEngineSupportConfiguration::class) 11 | annotation class EnableTaskpoolEngineSupport 12 | -------------------------------------------------------------------------------- /integration/camunda-bpm/springboot-autoconfigure/src/main/kotlin/io/holunda/polyflow/taskpool/TaskpoolEngineSupportConfiguration.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool 2 | 3 | import io.holunda.polyflow.datapool.EnableDataEntrySender 4 | import org.springframework.context.annotation.Configuration 5 | 6 | /** 7 | * Configuration enabling engine components. 8 | */ 9 | @EnableCamundaTaskpoolCollector 10 | @EnableDataEntrySender 11 | class TaskpoolEngineSupportConfiguration 12 | -------------------------------------------------------------------------------- /integration/camunda-bpm/springboot-autoconfigure/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | camunda: 2 | bpm: 3 | eventing: 4 | task: false 5 | -------------------------------------------------------------------------------- /integration/camunda-bpm/springboot-autoconfigure/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | I-Test using SpringBoot: ${spring-boot.version}, Camunda ${camunda.bpm.version} 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /integration/camunda-bpm/springboot-autoconfigure/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /integration/camunda-bpm/springboot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.holunda.polyflow.taskpool.collector.CamundaTaskpoolCollectorConfiguration 2 | io.holunda.polyflow.taskpool.sender.SenderConfiguration 3 | io.holunda.polyflow.datapool.DataEntrySenderConfiguration 4 | -------------------------------------------------------------------------------- /integration/camunda-bpm/springboot-starter/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | camunda: 2 | bpm: 3 | eventing: 4 | task: false 5 | -------------------------------------------------------------------------------- /integration/camunda-bpm/springboot-starter/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | I-Test using SpringBoot: ${spring-boot.version}, Camunda ${camunda.bpm.version} 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/CamundaEngineExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool 2 | 3 | import org.camunda.bpm.engine.context.ProcessEngineContext 4 | import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl 5 | import org.camunda.bpm.engine.impl.interceptor.Command 6 | import org.camunda.bpm.engine.impl.persistence.entity.IdentityLinkEntity 7 | import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity 8 | 9 | /** 10 | * Runs a command in command context. 11 | */ 12 | fun ProcessEngineConfigurationImpl.executeInCommandContext(command: Command): T { 13 | return this.commandExecutorTxRequired.execute(command) 14 | } 15 | /** 16 | * Execute call in a process engine context. 17 | * @param newContext if set to true, the new context is created. 18 | * @param call function to be called inside the process engine context. 19 | * @return T return value of the function. 20 | */ 21 | fun callInProcessEngineContext(newContext: Boolean, call: () -> T): T { 22 | return if (newContext) { 23 | try { 24 | ProcessEngineContext.requiresNew(); 25 | call.invoke() 26 | } finally { 27 | ProcessEngineContext.clear(); 28 | } 29 | } else { 30 | call.invoke() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/EnableCamundaTaskpoolCollector.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool 2 | 3 | import io.holunda.polyflow.taskpool.collector.CamundaTaskpoolCollectorConfiguration 4 | import org.springframework.context.annotation.Import 5 | 6 | /** 7 | * Enables the task collector, which listens to Camunda Spring Events and performs, collecting, enriching and sending 8 | * of taskpool commands to Task Pool Core. 9 | */ 10 | @MustBeDocumented 11 | @Import(CamundaTaskpoolCollectorConfiguration::class) 12 | @EnableTaskpoolSender 13 | annotation class EnableCamundaTaskpoolCollector 14 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/VariableMapExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool 2 | 3 | import org.camunda.bpm.engine.variable.VariableMap 4 | import org.camunda.bpm.engine.variable.Variables 5 | 6 | /** 7 | * Add all elements from one variable map to another. 8 | * @param source source of the variables. 9 | */ 10 | fun VariableMap.putAllTyped(source: VariableMap) { 11 | source.keys.forEach { 12 | this.putValueTyped(it, source.getValueTyped(it)) 13 | } 14 | } 15 | 16 | /** 17 | * Filters keys by a predicate. 18 | * @param predicate filter function. 19 | * @return new variable map containing only entries for which the keys are matching the filter function. 20 | */ 21 | inline fun VariableMap.filterKeys(predicate: (String) -> Boolean): VariableMap { 22 | val result = Variables.createVariables() 23 | for (entry in this) { 24 | if (predicate(entry.key)) { 25 | result[entry.key] = entry.value 26 | } 27 | } 28 | return result 29 | } 30 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/FallbackProcessVariablesCorrelatorConfiguration.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector 2 | 3 | import io.holunda.polyflow.taskpool.collector.task.enricher.ProcessVariablesCorrelator 4 | import org.camunda.bpm.spring.boot.starter.CamundaBpmAutoConfiguration 5 | import org.springframework.boot.autoconfigure.AutoConfigureAfter 6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean 7 | import org.springframework.context.annotation.Bean 8 | import org.springframework.context.annotation.Configuration 9 | 10 | /** 11 | * Configures fallback if no process variable correlator is defined. 12 | * No @Configuration required. 13 | * Configuration used via auto-configuration. 14 | */ 15 | @ConditionalOnMissingBean(ProcessVariablesCorrelator::class) 16 | class FallbackProcessVariablesCorrelatorConfiguration { 17 | /** 18 | * Empty correlator. 19 | */ 20 | @Bean 21 | fun processVariablesCorrelatorFallback(): ProcessVariablesCorrelator = ProcessVariablesCorrelator() 22 | } 23 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/FallbackProcessVariablesFilterConfiguration.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector 2 | 3 | import io.holunda.polyflow.taskpool.collector.task.enricher.ProcessVariablesFilter 4 | import org.camunda.bpm.spring.boot.starter.CamundaBpmAutoConfiguration 5 | import org.springframework.boot.autoconfigure.AutoConfigureAfter 6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean 7 | import org.springframework.context.annotation.Bean 8 | import org.springframework.context.annotation.Configuration 9 | 10 | /** 11 | * Configures fallback if no process variable filter is defined. 12 | * No @Configuration required. 13 | * Configuration used via auto-configuration. 14 | */ 15 | @ConditionalOnMissingBean(ProcessVariablesFilter::class) 16 | class FallbackProcessVariablesFilterConfiguration { 17 | /** 18 | * Empty process variable filter. 19 | */ 20 | @Bean 21 | fun processVariablesFilterFallback(): ProcessVariablesFilter = ProcessVariablesFilter() 22 | } 23 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/process/definition/ProcessDefinitionProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.process.definition 2 | 3 | import io.github.oshai.kotlinlogging.KotlinLogging 4 | import io.holunda.camunda.taskpool.api.process.definition.ProcessDefinitionCommand 5 | import io.holunda.polyflow.taskpool.sender.process.definition.ProcessDefinitionCommandSender 6 | import org.springframework.context.event.EventListener 7 | 8 | private val logger = KotlinLogging.logger {} 9 | 10 | /** 11 | * Processes commands sent via Spring Eventing and delegates them to taskpool command sender. 12 | */ 13 | class ProcessDefinitionProcessor( 14 | private val processDefinitionCommandSender: ProcessDefinitionCommandSender 15 | ) { 16 | 17 | /** 18 | * Receives the process definition command and pass it over to the sender. 19 | * @param command process definition command, delivered by Spring eventing. 20 | */ 21 | @EventListener 22 | fun process(command: ProcessDefinitionCommand) { 23 | if (logger.isTraceEnabled()) { 24 | logger.trace { "COLLECTOR-005: Sending process definition command: $command" } 25 | } 26 | processDefinitionCommandSender.send(command) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/process/definition/RefreshProcessDefinitionRegistrationParseListener.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.process.definition 2 | 3 | import io.holunda.polyflow.taskpool.executeInCommandContext 4 | import org.camunda.bpm.engine.impl.bpmn.parser.AbstractBpmnParseListener 5 | import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl 6 | import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity 7 | import org.camunda.bpm.engine.impl.util.xml.Element 8 | 9 | /** 10 | * Parse listener that starts a refresh process definition job on every new process parse (deployment). 11 | */ 12 | class RefreshProcessDefinitionRegistrationParseListener( 13 | private val processEngineConfiguration: ProcessEngineConfigurationImpl 14 | ) : AbstractBpmnParseListener() { 15 | 16 | override fun parseProcess(processElement: Element, processDefinition: ProcessDefinitionEntity) { 17 | // create job / send command to job executor 18 | // to handle this deployment asynchronous. 19 | processEngineConfiguration.executeInCommandContext(RefreshProcessDefinitionsJobCommand(processDefinitionKey = processDefinition.key)) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/process/instance/ProcessInstanceProcessor.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.process.instance 2 | 3 | import io.github.oshai.kotlinlogging.KotlinLogging 4 | import io.holunda.camunda.taskpool.api.process.instance.ProcessInstanceCommand 5 | import io.holunda.polyflow.taskpool.sender.process.instance.ProcessInstanceCommandSender 6 | import org.springframework.context.event.EventListener 7 | 8 | private val logger = KotlinLogging.logger {} 9 | 10 | /** 11 | * Default process instance processor. 12 | */ 13 | class ProcessInstanceProcessor( 14 | private val processInstanceCommandSender: ProcessInstanceCommandSender 15 | ) { 16 | 17 | /** 18 | * Reacts on incoming process instance commands. 19 | * @param command command about process instance to send. 20 | */ 21 | @EventListener 22 | fun process(command: ProcessInstanceCommand) { 23 | if (logger.isTraceEnabled()) { 24 | logger.trace { "COLLECTOR-006: Sending process instance command: $command" } 25 | } 26 | processInstanceCommandSender.send(command) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/TaskAssigner.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.task 2 | 3 | import io.holunda.camunda.taskpool.api.task.EngineTaskCommand 4 | 5 | /** 6 | * Hook for assignment changes. 7 | */ 8 | interface TaskAssigner { 9 | /** 10 | * Sets assignment of a task command. 11 | * @param command task command 12 | * @return command with modified assignment information. 13 | */ 14 | fun setAssignment(command: EngineTaskCommand): EngineTaskCommand 15 | } 16 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/VariablesEnricher.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.task 2 | 3 | import io.holunda.camunda.taskpool.api.task.TaskIdentityWithPayloadAndCorrelations 4 | 5 | /** 6 | * Enriches commands with payload. 7 | */ 8 | interface VariablesEnricher { 9 | /** 10 | * Enriches command with payload and correlations. 11 | */ 12 | fun enrich(command: T): T 13 | } 14 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/assigner/EmptyTaskAssigner.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.task.assigner 2 | 3 | import io.holunda.camunda.taskpool.api.task.EngineTaskCommand 4 | import io.holunda.polyflow.taskpool.collector.task.TaskAssigner 5 | 6 | /** 7 | * No-op task assigner changing nothing. 8 | */ 9 | class EmptyTaskAssigner : TaskAssigner { 10 | override fun setAssignment(command: EngineTaskCommand): EngineTaskCommand = command 11 | } 12 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/enricher/EmptyTaskCommandEnricher.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.task.enricher 2 | 3 | import io.holunda.camunda.taskpool.api.task.TaskIdentityWithPayloadAndCorrelations 4 | import io.holunda.polyflow.taskpool.collector.task.VariablesEnricher 5 | 6 | 7 | /** 8 | * Empty implementation without any enrichment. Used for compliance of the commands. 9 | */ 10 | class EmptyTaskCommandEnricher : VariablesEnricher { 11 | override fun enrich(command: T): T = command.apply { enriched = true } 12 | } 13 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/enricher/ProcessVariableCorrelation.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.task.enricher 2 | 3 | import io.holunda.camunda.taskpool.api.business.EntryType 4 | 5 | /** 6 | * Describes correlation between data entries for a business process definition. 7 | * @param processDefinitionKey process definition key. 8 | * @param correlations a map from task definition key to correlation map (variableName, entryType). 9 | * @param globalCorrelations a global (per-process) correlation map (variableName, entryType). 10 | */ 11 | data class ProcessVariableCorrelation( 12 | val processDefinitionKey: ProcessDefinitionKey, 13 | val correlations: Map>, 14 | val globalCorrelations: Map = emptyMap() 15 | ) 16 | 17 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/enricher/ProcessVariableFilter.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.task.enricher 2 | 3 | /** 4 | * This filter allows to either explicitly include (whitelist) or exclude (blacklist) process variables for all user tasks of a certain 5 | * process (if a process definition key is given), or for all user tasks of all processes (if no process definition key is given). 6 | * If a differentiation between individual user tasks of a process is required, use a {@link TaskVariableFilter} instead. 7 | */ 8 | data class ProcessVariableFilter( 9 | override val processDefinitionKey: ProcessDefinitionKey?, 10 | val filterType: FilterType, 11 | val processVariables: List = emptyList() 12 | ) : VariableFilter { 13 | 14 | constructor(filterType: FilterType, processVariables: List) : this(null, filterType, processVariables) 15 | 16 | override fun filter(taskDefinitionKey: TaskDefinitionKey, variableName: VariableName): Boolean { 17 | return (filterType == FilterType.INCLUDE) == processVariables.contains(variableName) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/kotlin/io/holunda/polyflow/taskpool/collector/task/enricher/VariableFilter.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.collector.task.enricher 2 | 3 | /** 4 | * To be implemented by classes that filter process variables. Used during enrichment to decide which process variables are added to a task's payload. 5 | */ 6 | interface VariableFilter { 7 | 8 | val processDefinitionKey: ProcessDefinitionKey? 9 | 10 | /** 11 | * Returns whether the process variable with the given name shall be contained in the payload of the given task. 12 | * @param taskDefinitionKey the key of the task to be enriched 13 | * @param variableName the name of the process variable 14 | */ 15 | fun filter(taskDefinitionKey: TaskDefinitionKey, variableName: VariableName): Boolean 16 | 17 | } 18 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.holunda.polyflow.taskpool.collector.FallbackProcessVariablesCorrelatorConfiguration 2 | io.holunda.polyflow.taskpool.collector.FallbackProcessVariablesFilterConfiguration 3 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/test/kotlin/io/holunda/polyflow/taskpool/itest/JacksonDataFormatConfigurator.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.itest 2 | 3 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule 4 | import com.fasterxml.jackson.module.kotlin.KotlinModule 5 | import org.camunda.spin.impl.json.jackson.format.JacksonJsonDataFormat 6 | import org.camunda.spin.spi.DataFormatConfigurator 7 | 8 | class JacksonDataFormatConfigurator : DataFormatConfigurator { 9 | 10 | override fun configure(dataFormat: JacksonJsonDataFormat) { 11 | val objectMapper = dataFormat.objectMapper 12 | objectMapper.registerModule(KotlinModule.Builder().build()) 13 | objectMapper.registerModule(JavaTimeModule()) 14 | } 15 | 16 | override fun getDataFormatClass(): Class { 17 | return JacksonJsonDataFormat::class.java 18 | } 19 | } -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/test/resources/META-INF/services/org.camunda.spin.spi.DataFormatConfigurator: -------------------------------------------------------------------------------- 1 | io.holunda.polyflow.taskpool.itest.JacksonDataFormatConfigurator 2 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/test/resources/application-properties-itest.yml: -------------------------------------------------------------------------------- 1 | # 2 | # I-Test properties justifying that no properties are needed to start Spring Boot with Camunda Task Pool collector. 3 | # 4 | spring: 5 | application: 6 | name: Foo 7 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | I-Test using SpringBoot: ${spring-boot.version}, Camunda ${camunda.bpm.version} 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-collector/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-job-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/EngineTaskCommandsSendingJobHandlerConfiguration.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper 4 | import com.fasterxml.jackson.module.kotlin.readValue 5 | import org.camunda.bpm.engine.impl.jobexecutor.JobHandlerConfiguration 6 | 7 | /** 8 | * Configuration for a job handler sending commands to Taskpool Core. 9 | * @param taskId for what task id we are sending commands 10 | * @param commandByteArrayId reference to the resource entity in ACT_GE_BYTEARRAY storing byte serialized JSON of List. 11 | */ 12 | data class EngineTaskCommandsSendingJobHandlerConfiguration( 13 | val taskId: String, 14 | val commandByteArrayId: String 15 | ) : JobHandlerConfiguration { 16 | 17 | companion object { 18 | /** 19 | * Reconstructs the configuration from JSON String. 20 | */ 21 | fun fromCanonicalString(value: String, objectMapper: ObjectMapper): EngineTaskCommandsSendingJobHandlerConfiguration { 22 | return objectMapper.readValue(value) 23 | } 24 | } 25 | 26 | // will never be used. 27 | override fun toCanonicalString(): String = throw UnsupportedOperationException() 28 | } -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-job-sender/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.holunda.polyflow.taskpool.sender.CamundaJobSenderConfiguration 2 | -------------------------------------------------------------------------------- /integration/camunda-bpm/taskpool-job-sender/src/test/kotlin/io/holunda/polyflow/taskpool/sender/EngineTaskCommandsSendingJobHandlerConfigurationTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender 2 | 3 | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper 4 | import com.fasterxml.jackson.module.kotlin.readValue 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.junit.jupiter.api.Test 7 | 8 | class EngineTaskCommandsSendingJobHandlerConfigurationTest { 9 | 10 | private val objectMapper = jacksonObjectMapper() 11 | 12 | @Test 13 | fun `serializes configuration`() { 14 | val config = EngineTaskCommandsSendingJobHandlerConfiguration( 15 | taskId = "4711", 16 | commandByteArrayId = "0815" 17 | ) 18 | 19 | val json = objectMapper.writeValueAsString(config) 20 | assertThat(json).isEqualTo("""{"taskId":"4711","commandByteArrayId":"0815"}""") 21 | 22 | val back: EngineTaskCommandsSendingJobHandlerConfiguration = objectMapper.readValue(json) 23 | assertThat(back).isEqualTo(config) 24 | } 25 | } -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/main/kotlin/io/holunda/polyflow/datapool/DataEntrySenderType.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool 2 | 3 | /** 4 | * Data entry sender type. 5 | */ 6 | enum class DataEntrySenderType { 7 | /** 8 | * Provided implementation. 9 | */ 10 | simple, 11 | 12 | /** 13 | * Sender using Tx synchronization sending commands directly. 14 | */ 15 | tx, 16 | 17 | /** 18 | * Custom = user-defined. 19 | */ 20 | custom 21 | } 22 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/main/kotlin/io/holunda/polyflow/datapool/DataPoolSenderProperties.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | import org.springframework.boot.context.properties.NestedConfigurationProperty 5 | 6 | /** 7 | * Holder for the enabled flag and the reference to the relevant [DataPoolSenderProperties]. 8 | * The name is special in order to avoid name clashing with taskpool sender properties. 9 | */ 10 | @ConfigurationProperties(prefix = "polyflow.integration.sender") 11 | data class DataPoolSenderProperties( 12 | /** 13 | * Global value to control the command gateway. 14 | */ 15 | val enabled: Boolean = true, 16 | 17 | /** 18 | * Data entry properties. 19 | */ 20 | @NestedConfigurationProperty 21 | val dataEntry: DataEntrySenderProperties = DataEntrySenderProperties(), 22 | ) 23 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/main/kotlin/io/holunda/polyflow/datapool/EnableDataEntrySender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool 2 | 3 | import org.springframework.context.annotation.Import 4 | 5 | /** 6 | * Enables the data entry sender. 7 | */ 8 | @MustBeDocumented 9 | @Import(DataEntrySenderConfiguration::class) 10 | annotation class EnableDataEntrySender 11 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/main/kotlin/io/holunda/polyflow/datapool/projector/DataEntryProjector.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.projector 2 | 3 | import io.holunda.camunda.taskpool.api.business.EntryType 4 | import org.springframework.stereotype.Component 5 | 6 | /** 7 | * Component responsible for retrieving property projectors for given entry types. 8 | */ 9 | class DataEntryProjector(private val suppliers: List) { 10 | /** 11 | * Retrieve a list of projection suppliers for a given entry type. 12 | * @return a projection supplier if registered for this entry type, or null. 13 | */ 14 | fun getProjection(entryType: EntryType): DataEntryProjectionSupplier? = suppliers.find { it.entryType == entryType } 15 | } 16 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/main/kotlin/io/holunda/polyflow/datapool/sender/SimpleDataEntryCommandSender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.sender 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper 4 | import io.holunda.polyflow.datapool.DataEntrySenderProperties 5 | import io.holunda.polyflow.datapool.projector.DataEntryProjector 6 | import io.holunda.polyflow.datapool.sender.gateway.CommandListGateway 7 | import org.axonframework.commandhandling.CommandMessage 8 | 9 | /** 10 | * Sends commands using the gateway. 11 | */ 12 | class SimpleDataEntryCommandSender( 13 | private val commandListGateway: CommandListGateway, 14 | properties: DataEntrySenderProperties, 15 | dataEntryProjector: DataEntryProjector, 16 | objectMapper: ObjectMapper 17 | ) : AbstractDataEntryCommandSender(properties, dataEntryProjector, objectMapper) { 18 | 19 | override fun send(command: CommandMessage) { 20 | if (properties.enabled) { 21 | commandListGateway.sendToGateway(listOf(command)) 22 | } else { 23 | DataEntryCommandSender.logger.debug { "SENDER-104: Data entry sending is disabled by property. Would have sent $command." } 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/main/kotlin/io/holunda/polyflow/datapool/sender/gateway/CommandListGateway.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.sender.gateway 2 | 3 | import org.axonframework.commandhandling.CommandResultMessage 4 | import java.util.function.BiFunction 5 | 6 | /** 7 | * Defines a gateway proxy, for sending commands. 8 | */ 9 | interface CommandListGateway { 10 | 11 | /** 12 | * Sends a list of commands to gateway. 13 | */ 14 | fun sendToGateway(commands: List) 15 | 16 | } 17 | 18 | /** 19 | * Handler for command errors. 20 | */ 21 | interface CommandErrorHandler : BiFunction, Unit> 22 | 23 | /** 24 | * Handler for command results. 25 | */ 26 | interface CommandSuccessHandler : BiFunction, Unit> 27 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/main/kotlin/io/holunda/polyflow/datapool/sender/gateway/LoggingDataEntryCommandErrorHandler.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.sender.gateway 2 | 3 | import io.github.oshai.kotlinlogging.KLogger 4 | import org.axonframework.commandhandling.CommandResultMessage 5 | import org.slf4j.Logger 6 | 7 | /** 8 | * Error handler, logging the error. 9 | */ 10 | open class LoggingDataEntryCommandErrorHandler(private val logger: KLogger) : CommandErrorHandler { 11 | 12 | override fun apply(commandMessage: Any, commandResultMessage: CommandResultMessage) { 13 | logger.error(commandResultMessage.exceptionResult()) { "${"SENDER-103: Sending command $commandMessage resulted in error"}" } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/main/kotlin/io/holunda/polyflow/datapool/sender/gateway/LoggingDataEntryCommandSuccessHandler.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool.sender.gateway 2 | 3 | import io.github.oshai.kotlinlogging.KLogger 4 | import org.axonframework.commandhandling.CommandResultMessage 5 | import org.slf4j.Logger 6 | 7 | /** 8 | * Logs success. 9 | */ 10 | open class LoggingDataEntryCommandSuccessHandler(private val logger: KLogger) : CommandSuccessHandler { 11 | 12 | override fun apply(commandMessage: Any, commandResultMessage: CommandResultMessage) { 13 | if (logger.isDebugEnabled()) { 14 | logger.debug { "SENDER-102: Successfully submitted command $commandMessage" } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/test/kotlin/io/holunda/polyflow/datapool/DataEntryDataPoolSenderPropertiesITest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.junit.jupiter.api.Test 5 | import org.junit.jupiter.api.extension.ExtendWith 6 | import org.springframework.beans.factory.annotation.Autowired 7 | import org.springframework.boot.test.context.SpringBootTest 8 | import org.springframework.context.annotation.PropertySource 9 | import org.springframework.test.context.ActiveProfiles 10 | import org.springframework.test.context.junit.jupiter.SpringExtension 11 | 12 | @ExtendWith(SpringExtension::class) 13 | @SpringBootTest(classes = [PropertiesTestApplication::class], webEnvironment = SpringBootTest.WebEnvironment.MOCK) 14 | @ActiveProfiles("properties-itest") 15 | @PropertySource 16 | class DataEntryDataPoolSenderPropertiesITest { 17 | 18 | @Autowired 19 | lateinit var props: DataEntrySenderProperties 20 | 21 | @Test 22 | fun `should use defaults without properties in yaml`() { 23 | assertThat(props.applicationName).isEqualTo("Foo") 24 | assertThat(props.enabled).isFalse 25 | assertThat(props.type).isEqualTo(DataEntrySenderType.simple) 26 | assertThat(props.sendWithinTransaction).isFalse() 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/test/kotlin/io/holunda/polyflow/datapool/PropertiesTestApplication.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.datapool 2 | 3 | import io.holunda.polyflow.spring.ApplicationNameBeanPostProcessor 4 | import org.springframework.boot.autoconfigure.SpringBootApplication 5 | import org.springframework.boot.context.properties.EnableConfigurationProperties 6 | import org.springframework.context.annotation.Import 7 | 8 | @SpringBootApplication 9 | @EnableConfigurationProperties(DataEntrySenderProperties::class) 10 | @Import(ApplicationNameBeanPostProcessor::class) 11 | class PropertiesTestApplication 12 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/test/resources/application-properties-itest.yml: -------------------------------------------------------------------------------- 1 | # 2 | # I-Test properties justifying that no properties are needed to start Spring Boot with Camunda Task Pool collector. 3 | # 4 | spring: 5 | application: 6 | name: Foo 7 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | I-Test using SpringBoot: ${spring-boot.version} 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /integration/common/datapool-sender/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /integration/common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | io.holunda.polyflow 8 | polyflow-parent 9 | 4.4.1-SNAPSHOT 10 | ../../bom/parent/pom.xml 11 | 12 | 13 | polyflow-integration-common-parent 14 | POM: integration/${project.artifactId} 15 | pom 16 | 17 | 18 | datapool-sender 19 | tasklist-url-resolver 20 | taskpool-sender 21 | variable-serializer 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /integration/common/tasklist-url-resolver/src/main/kotlin/io/holunda/polyflow/urlresolver/FallbackTasklistUrlResolverAutoConfiguration.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.urlresolver 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties 5 | import org.springframework.context.annotation.Bean 6 | 7 | 8 | /** 9 | * No @Configuration required. 10 | * Configuration used via auto-configuration. 11 | */ 12 | @EnableConfigurationProperties(TasklistUrlProperties::class) 13 | class FallbackTasklistUrlResolverAutoConfiguration { 14 | 15 | /** 16 | * Property-based Tasklist URL resolver. 17 | */ 18 | @Bean 19 | @ConditionalOnMissingBean(TasklistUrlResolver::class) 20 | fun propertyBasedTasklistUrlResolver(properties: TasklistUrlProperties): TasklistUrlResolver { 21 | return if (properties.tasklistUrl == null) { 22 | throw IllegalStateException("Either set polyflow.integration.tasklist.tasklist-url property or provide own implementation of TasklistUrlResolver") 23 | } else { 24 | object : TasklistUrlResolver { 25 | override fun getTasklistUrl(): String = properties.tasklistUrl 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /integration/common/tasklist-url-resolver/src/main/kotlin/io/holunda/polyflow/urlresolver/TasklistUrlProperties.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.urlresolver 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | 5 | /** 6 | * Configuration properties for task list URL. 7 | */ 8 | @ConfigurationProperties(prefix = "polyflow.integration.tasklist") 9 | data class TasklistUrlProperties( 10 | /** 11 | * URL of the task list. 12 | */ 13 | val tasklistUrl: String? = null 14 | ) 15 | -------------------------------------------------------------------------------- /integration/common/tasklist-url-resolver/src/main/kotlin/io/holunda/polyflow/urlresolver/TasklistUrlResolver.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.urlresolver 2 | 3 | /** 4 | * Resolver for tasklist URL. 5 | */ 6 | interface TasklistUrlResolver { 7 | /** 8 | * Retrieves the URL of the task list application. 9 | * @return task list URL 10 | */ 11 | fun getTasklistUrl() : String 12 | } 13 | -------------------------------------------------------------------------------- /integration/common/tasklist-url-resolver/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | io.holunda.polyflow.urlresolver.FallbackTasklistUrlResolverAutoConfiguration 2 | -------------------------------------------------------------------------------- /integration/common/tasklist-url-resolver/src/test/kotlin/io/holunda/polyflow/urlresolver/DataEntrySenderPropertiesITest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.urlresolver 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.junit.jupiter.api.Test 5 | import org.junit.jupiter.api.extension.ExtendWith 6 | import org.springframework.beans.factory.annotation.Autowired 7 | import org.springframework.boot.test.context.SpringBootTest 8 | import org.springframework.context.annotation.PropertySource 9 | import org.springframework.test.context.ActiveProfiles 10 | import org.springframework.test.context.junit.jupiter.SpringExtension 11 | 12 | @ExtendWith(SpringExtension::class) 13 | @SpringBootTest(classes = [PropertiesTestApplication::class], webEnvironment = SpringBootTest.WebEnvironment.MOCK) 14 | @ActiveProfiles("properties-itest") 15 | @PropertySource 16 | class DataEntrySenderPropertiesITest { 17 | 18 | @Autowired 19 | lateinit var props: TasklistUrlProperties 20 | 21 | @Test 22 | fun `should use defaults without properties in yaml`() { 23 | assertThat(props.tasklistUrl).isNull() 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /integration/common/tasklist-url-resolver/src/test/kotlin/io/holunda/polyflow/urlresolver/PropertiesTestApplication.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.urlresolver 2 | 3 | import org.mockito.kotlin.mock 4 | import org.springframework.boot.autoconfigure.SpringBootApplication 5 | import org.springframework.boot.context.properties.EnableConfigurationProperties 6 | import org.springframework.context.annotation.Bean 7 | 8 | @SpringBootApplication 9 | @EnableConfigurationProperties(TasklistUrlProperties::class) 10 | class PropertiesTestApplication { 11 | 12 | @Bean 13 | fun ownResolver(): TasklistUrlResolver = mock() 14 | 15 | } 16 | -------------------------------------------------------------------------------- /integration/common/tasklist-url-resolver/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | I-Test using SpringBoot: ${spring-boot.version} 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /integration/common/tasklist-url-resolver/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/EnableTaskpoolSender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool 2 | 3 | import io.holunda.polyflow.taskpool.sender.SenderConfiguration 4 | import org.springframework.context.annotation.Import 5 | 6 | /** 7 | * Enables the taskpool sender. 8 | */ 9 | @MustBeDocumented 10 | @Import(SenderConfiguration::class) 11 | annotation class EnableTaskpoolSender 12 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/JacksonExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper 4 | import io.holunda.polyflow.bus.jackson.configurePolyflowJacksonObjectMapper 5 | 6 | /** 7 | * Configures object mapper. 8 | */ 9 | @Deprecated( 10 | replaceWith = ReplaceWith("io.holunda.polyflow.bus.jackson.configurePolyflowJacksonObjectMapper()"), 11 | message = "Moved to separate artifact polyflow-bus-jackson to centralize the creation" 12 | ) 13 | fun ObjectMapper.configureTaskpoolJacksonObjectMapper(): ObjectMapper = configurePolyflowJacksonObjectMapper() 14 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/ProcessInstanceValueExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper 4 | import io.holunda.camunda.taskpool.api.process.variable.ObjectProcessVariableValue 5 | import io.holunda.camunda.taskpool.api.process.variable.PrimitiveProcessVariableValue 6 | import io.holunda.camunda.taskpool.api.process.variable.ProcessVariableValue 7 | import io.holunda.camunda.taskpool.api.process.variable.TypedValueProcessVariableValue 8 | import io.holunda.camunda.variable.serializer.serialize 9 | 10 | /** 11 | * Serialize process variable. 12 | */ 13 | fun ProcessVariableValue.serialize(objectMapper: ObjectMapper): ProcessVariableValue = 14 | if (this is TypedValueProcessVariableValue) { 15 | if (this.value.type.isPrimitiveValueType) { 16 | PrimitiveProcessVariableValue(this.value.value) 17 | } else { 18 | ObjectProcessVariableValue(serialize(this.value.value, objectMapper)) 19 | } 20 | } else { 21 | this 22 | } 23 | 24 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/gateway/CommandListGateway.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.gateway 2 | 3 | import org.axonframework.commandhandling.CommandResultMessage 4 | import java.util.function.BiFunction 5 | 6 | /** 7 | * Defines a gateway proxy, for sending commands. 8 | */ 9 | interface CommandListGateway { 10 | 11 | /** 12 | * Sends a list of commands to gateway. 13 | */ 14 | fun sendToGateway(commands: List) 15 | 16 | } 17 | 18 | /** 19 | * Handler for command errors. 20 | */ 21 | interface CommandErrorHandler : BiFunction, Unit> 22 | 23 | /** 24 | * Handler for command results. 25 | */ 26 | interface CommandSuccessHandler : BiFunction, Unit> 27 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/gateway/LoggingTaskCommandErrorHandler.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.gateway 2 | 3 | import io.github.oshai.kotlinlogging.KLogger 4 | import org.axonframework.commandhandling.CommandResultMessage 5 | 6 | /** 7 | * Error handler, logging the error. 8 | */ 9 | open class LoggingTaskCommandErrorHandler(private val logger: KLogger) : CommandErrorHandler { 10 | 11 | override fun apply(commandMessage: Any, commandResultMessage: CommandResultMessage) { 12 | logger.error(commandResultMessage.exceptionResult()) { "SENDER-003: Sending command $commandMessage resulted in error" } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/gateway/LoggingTaskCommandSuccessHandler.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.gateway 2 | 3 | import io.github.oshai.kotlinlogging.KLogger 4 | import org.axonframework.commandhandling.CommandResultMessage 5 | 6 | /** 7 | * Logs success. 8 | */ 9 | open class LoggingTaskCommandSuccessHandler(private val logger: KLogger) : CommandSuccessHandler { 10 | 11 | override fun apply(commandMessage: Any, commandResultMessage: CommandResultMessage) { 12 | if (logger.isDebugEnabled()) { 13 | logger.debug { "SENDER-002: Successfully submitted command $commandMessage" } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/process/definition/ProcessDefinitionCommandSender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.process.definition 2 | 3 | import io.holunda.camunda.taskpool.api.process.definition.ProcessDefinitionCommand 4 | 5 | /** 6 | * Sender for process definitions. 7 | */ 8 | interface ProcessDefinitionCommandSender { 9 | 10 | /** 11 | * Sends a process definition command. 12 | * @param command command to send. 13 | */ 14 | fun send(command: ProcessDefinitionCommand) 15 | } 16 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/process/definition/SimpleProcessDefinitionCommandSender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.process.definition 2 | 3 | import io.github.oshai.kotlinlogging.KotlinLogging 4 | import io.holunda.camunda.taskpool.api.process.definition.ProcessDefinitionCommand 5 | import io.holunda.polyflow.taskpool.sender.SenderProperties 6 | import io.holunda.polyflow.taskpool.sender.gateway.CommandListGateway 7 | 8 | private val logger = KotlinLogging.logger {} 9 | 10 | /** 11 | * Simple sender for process definition commands 12 | */ 13 | internal class SimpleProcessDefinitionCommandSender( 14 | private val commandListGateway: CommandListGateway, 15 | private val senderProperties: SenderProperties 16 | ) : ProcessDefinitionCommandSender { 17 | 18 | override fun send(command: ProcessDefinitionCommand) { 19 | if (senderProperties.enabled && senderProperties.processDefinition.enabled) { 20 | commandListGateway.sendToGateway(listOf(command)) 21 | } else { 22 | logger.debug { "SENDER-007: Process definition sending is disabled by property. Would have sent $command." } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/process/instance/ProcessInstanceCommandSender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.process.instance 2 | 3 | import io.holunda.camunda.taskpool.api.process.instance.ProcessInstanceCommand 4 | 5 | /** 6 | * Sender for process instances. 7 | */ 8 | interface ProcessInstanceCommandSender { 9 | 10 | /** 11 | * Sends a process instance command. 12 | * @param command command to send. 13 | */ 14 | fun send(command: ProcessInstanceCommand) 15 | } 16 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/process/instance/SimpleProcessInstanceCommandSender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.process.instance 2 | 3 | import io.github.oshai.kotlinlogging.KotlinLogging 4 | import io.holunda.camunda.taskpool.api.process.instance.ProcessInstanceCommand 5 | import io.holunda.polyflow.taskpool.sender.SenderProperties 6 | import io.holunda.polyflow.taskpool.sender.gateway.CommandListGateway 7 | 8 | private val logger = KotlinLogging.logger {} 9 | 10 | /** 11 | * Simple sender for process definition commands 12 | */ 13 | internal class SimpleProcessInstanceCommandSender( 14 | private val commandListGateway: CommandListGateway, 15 | private val senderProperties: SenderProperties 16 | ) : ProcessInstanceCommandSender { 17 | 18 | override fun send(command: ProcessInstanceCommand) { 19 | if (senderProperties.enabled && senderProperties.processInstance.enabled) { 20 | commandListGateway.sendToGateway(listOf(command)) 21 | } else { 22 | logger.debug { "SENDER-008: Process instance sending is disabled by property. Would have sent $command." } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/process/variable/ProcessVariableCommandSender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.process.variable 2 | 3 | /** 4 | * Sender for process variables. 5 | */ 6 | interface ProcessVariableCommandSender { 7 | /** 8 | * Sends a process variable command. 9 | * @param command command to send. 10 | */ 11 | fun send(command: SingleProcessVariableCommand) 12 | } 13 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/task/EngineTaskCommandSender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.task 2 | 3 | import io.holunda.camunda.taskpool.api.task.EngineTaskCommand 4 | 5 | /** 6 | * Interface for beans sending task commands. 7 | */ 8 | interface EngineTaskCommandSender { 9 | /** 10 | * Sends the command to core and enriches it, if possible. 11 | */ 12 | fun send(command: EngineTaskCommand) 13 | } 14 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/task/SimpleEngineTaskCommandSender.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.task 2 | 3 | import io.github.oshai.kotlinlogging.KotlinLogging 4 | import io.holunda.camunda.taskpool.api.task.EngineTaskCommand 5 | import io.holunda.polyflow.taskpool.sender.SenderProperties 6 | import io.holunda.polyflow.taskpool.sender.gateway.CommandListGateway 7 | 8 | private val logger = KotlinLogging.logger {} 9 | 10 | /** 11 | * Sends commands using the gateway. 12 | */ 13 | class SimpleEngineTaskCommandSender( 14 | private val commandListGateway: CommandListGateway, 15 | private val senderProperties: SenderProperties 16 | ) : EngineTaskCommandSender { 17 | 18 | override fun send(command: EngineTaskCommand) { 19 | if (senderProperties.task.enabled) { 20 | commandListGateway.sendToGateway(listOf(command)) 21 | } else { 22 | logger.debug { "SENDER-004: Process task sending is disabled by property. Would have sent $command." } 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/task/accumulator/CommandAccumulator.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.task.accumulator 2 | 3 | import io.holunda.camunda.taskpool.api.task.EngineTaskCommand 4 | 5 | /** 6 | * Accumulator is responsible for transforming (and evtl. reducing) the number of commands being sent, 7 | * by accumulating information from several commands into one. 8 | */ 9 | typealias EngineTaskCommandAccumulator = (List) -> List 10 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/task/accumulator/EngineTaskCommandIntentDetector.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.task.accumulator 2 | 3 | import io.holunda.camunda.taskpool.api.task.EngineTaskCommand 4 | 5 | /** 6 | * Detects intents of task command lists. 7 | */ 8 | interface EngineTaskCommandIntentDetector { 9 | 10 | /** 11 | * Detects intents from a list of tasks commands collected for a single user task id. 12 | * @param engineTaskCommands commands collected from the engine. 13 | * @return list of intents. Every intent is a list of corresponding task commands sorted in a way, that the intended command is the first element in the list. 14 | */ 15 | fun detectIntents(engineTaskCommands: List): List> 16 | } -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/task/accumulator/EngineTaskCommandProjectionErrorDetector.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.task.accumulator 2 | 3 | import io.holunda.camunda.taskpool.api.task.* 4 | 5 | /** 6 | * Due to Camunda event handling implementation eventing might be slightly strange. 7 | * Ignore error reporting if: 8 | * - to any original (intent) the detail is UpdateAttributesHistoricTaskCommand 9 | * - to any original except create the detail is AddCandidateUsersCommand, DeleteCandidateUsersCommand, since the detail should be detected as primary intent 10 | */ 11 | object EngineTaskCommandProjectionErrorDetector : ProjectionErrorDetector { 12 | 13 | override fun shouldReportError(original: Any, detail: Any): Boolean { 14 | return when { 15 | original !is CreateTaskCommand && detail is AddCandidateUsersCommand -> false 16 | original !is CreateTaskCommand && detail is DeleteCandidateUsersCommand -> false 17 | detail is UpdateAttributesHistoricTaskCommand -> false 18 | else -> true 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/main/kotlin/io/holunda/polyflow/taskpool/sender/task/accumulator/SortingCommandAccumulator.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender.task.accumulator 2 | 3 | import io.holunda.camunda.taskpool.api.task.EngineTaskCommand 4 | import io.holunda.camunda.taskpool.api.task.EngineTaskCommandSorter 5 | 6 | /** 7 | * Sorts commands by their order id 8 | */ 9 | class SortingCommandAccumulator : EngineTaskCommandAccumulator { 10 | override fun invoke(taskCommands: List) = taskCommands.sortedWith(EngineTaskCommandSorter()) 11 | } 12 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/test/kotlin/io/holunda/polyflow/taskpool/sender/PropertiesTestApplication.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.taskpool.sender 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties 5 | 6 | @SpringBootApplication 7 | @EnableConfigurationProperties(SenderProperties::class) 8 | class PropertiesTestApplication 9 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | I-Test using SpringBoot: ${spring-boot.version} 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /integration/common/taskpool-sender/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /integration/common/variable-serializer/src/test/kotlin/TestFixtures.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.variable.serializer 2 | 3 | import java.time.Instant 4 | import java.time.OffsetDateTime 5 | 6 | data class Pojo1( 7 | val key: String, 8 | val anotherKey: List 9 | ) 10 | 11 | data class Pojo2( 12 | val keyZUZUZ: String, 13 | var children: List = listOf() 14 | ) 15 | 16 | data class Pojo3( 17 | val key: String, 18 | val anotherKey: Int 19 | ) 20 | 21 | data class Pojo4( 22 | val key: String, 23 | val anotherKey: List 24 | ) 25 | 26 | data class Pojo5( 27 | val key: String, 28 | val ts: Instant, 29 | val date: OffsetDateTime 30 | ) 31 | -------------------------------------------------------------------------------- /view/form-url-resolver/src/main/kotlin/io/holunda/polyflow/urlresolver/EnablePropertyBasedFormUrlResolver.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.urlresolver 2 | 3 | import org.springframework.context.annotation.Import 4 | 5 | /** 6 | * Annotation to enable property-based form url resolver component. 7 | */ 8 | @MustBeDocumented 9 | @Import(PropertyBasedFormUrlResolverConfiguration::class) 10 | annotation class EnablePropertyBasedFormUrlResolver 11 | -------------------------------------------------------------------------------- /view/form-url-resolver/src/test/resources/form-url-properties.yml: -------------------------------------------------------------------------------- 1 | polyflow: 2 | integration: 3 | form-url-resolver: 4 | defaultTaskTemplate: "/forms/${formKey}/${id}" 5 | defaultApplicationTemplate: "http://localhost:8080/${applicatioName}" 6 | defaultProcessTemplate: "/${processDefinitionKey}/${formKey}" 7 | applications: 8 | - app1: 9 | url: "http://app1.server.io/app" 10 | tasks: 11 | - task1: "/forms/task1/foo/${id}" 12 | - task2: "/bar/2/foo/${id}" 13 | processes: 14 | - process1: "/proc-1/start" 15 | - process2: "/proc/2/begin" 16 | - app2: 17 | url: "http://foo.app2.com" 18 | tasks: 19 | - otherTask1: "/views/task1/${id}" 20 | - otherTask2: "/other/2/foo/${id}" 21 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/CountByApplication.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa 2 | 3 | /** 4 | * Helper multi-valued class to support count by application name queries. 5 | */ 6 | data class CountByApplication( 7 | /** 8 | * application name (grouping criteria). 9 | */ 10 | val applicationName: String, 11 | /** 12 | * Count. 13 | */ 14 | val count: Long 15 | ) 16 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/EnablePolyflowJpaView.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa 2 | 3 | import org.springframework.context.annotation.Import 4 | 5 | /** 6 | * Enables polyflow projection using RDMBS via JPA as persistence. 7 | */ 8 | @MustBeDocumented 9 | @Import(PolyflowJpaViewConfiguration::class) 10 | annotation class EnablePolyflowJpaView 11 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/auth/AuthorizationPrincipal.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.auth 2 | 3 | /** 4 | * DTO representing authorized user or group. 5 | */ 6 | data class AuthorizationPrincipal( 7 | val name: String, 8 | val type: AuthorizationPrincipalType 9 | ) { 10 | companion object { 11 | /** 12 | * Factory method to construct principal out of string. 13 | */ 14 | operator fun invoke(auth: String) = auth.split(":").let { 15 | require(it.size >= 2) { "Illegal auth format, expecting :, received '$auth'" } 16 | AuthorizationPrincipal(type = AuthorizationPrincipalType.valueOf(it[0]), name = it.subList(1, it.size).joinToString(":")) 17 | } 18 | 19 | /** 20 | * Constructor for the group principal. 21 | */ 22 | fun group(name: String): AuthorizationPrincipal = AuthorizationPrincipal(name = name, type = AuthorizationPrincipalType.GROUP) 23 | /** 24 | * Constructor for the user principal. 25 | */ 26 | fun user(name: String): AuthorizationPrincipal = AuthorizationPrincipal(name = name, type = AuthorizationPrincipalType.USER) 27 | } 28 | 29 | override fun toString(): String = "$type:$name" 30 | } 31 | 32 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/auth/AuthorizationPrincipalType.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.auth 2 | 3 | /** 4 | * Authorization principal type. 5 | */ 6 | enum class AuthorizationPrincipalType { 7 | GROUP, 8 | USER 9 | } 10 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryEventHandler.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.data 2 | 3 | import io.holunda.camunda.taskpool.api.business.DataEntryAnonymizedEvent 4 | import io.holunda.camunda.taskpool.api.business.DataEntryCreatedEvent 5 | import io.holunda.camunda.taskpool.api.business.DataEntryDeletedEvent 6 | import io.holunda.camunda.taskpool.api.business.DataEntryUpdatedEvent 7 | import org.axonframework.messaging.MetaData 8 | import java.time.Instant 9 | 10 | /** 11 | * Interface for receiving all data entry relevant events. 12 | */ 13 | interface DataEntryEventHandler { 14 | 15 | /** 16 | * Data entry created. 17 | */ 18 | fun on(event: DataEntryCreatedEvent, metaData: MetaData, eventTimestamp: Instant) 19 | 20 | /** 21 | * Data entry updated. 22 | */ 23 | fun on(event: DataEntryUpdatedEvent, metaData: MetaData, eventTimestamp: Instant) 24 | 25 | /** 26 | * Data entry deleted. 27 | */ 28 | fun on(event: DataEntryDeletedEvent, metaData: MetaData) 29 | 30 | /** 31 | * Data entry anonymized. 32 | */ 33 | fun on(event: DataEntryAnonymizedEvent, metaData: MetaData) 34 | } 35 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryPayloadAttributeEntity.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.data 2 | 3 | import jakarta.persistence.EmbeddedId 4 | import jakarta.persistence.Entity 5 | import jakarta.persistence.Table 6 | import org.hibernate.annotations.Immutable 7 | 8 | /** 9 | * Entity that holds the combined payload attributes of the correlated DataEntries. 10 | */ 11 | @Entity 12 | @Immutable 13 | @Table(name = "PLF_VIEW_DATA_ENTRY_PAYLOAD") 14 | class DataEntryPayloadAttributeEntity( 15 | @EmbeddedId 16 | var id: DataEntryPayloadAttributeEntityId, 17 | ) { 18 | constructor(entryType: String, entryId: String, path: String, value: String) : this( 19 | DataEntryPayloadAttributeEntityId( 20 | entryType = entryType, 21 | entryId = entryId, 22 | path = path, 23 | value = value 24 | ) 25 | ) 26 | 27 | override fun toString(): String = "DataEntryPayloadAttributeEntity(id=$id)" 28 | } 29 | 30 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryStateEmbeddable.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.data 2 | 3 | import io.holunda.camunda.taskpool.api.business.DataEntryState 4 | import jakarta.persistence.Column 5 | import jakarta.persistence.Embeddable 6 | import java.io.Serializable 7 | 8 | /** 9 | * Represents stat of data entry. 10 | */ 11 | @Embeddable 12 | class DataEntryStateEmbeddable( 13 | @Column(name = "PROCESSING_TYPE", length = 64, nullable = false) 14 | var processingType: String, 15 | @Column(name = "STATE", length = 64, nullable = false) 16 | var state: String 17 | ) : Serializable { 18 | companion object { 19 | /** 20 | * Factory method. 21 | */ 22 | operator fun invoke(state: DataEntryState): DataEntryStateEmbeddable = 23 | DataEntryStateEmbeddable(processingType = state.processingType.name, state = state.state ?: "") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessDefinitionRepository.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.process 2 | 3 | import io.holunda.polyflow.view.jpa.auth.AuthorizationPrincipal 4 | import io.holunda.polyflow.view.jpa.composeOr 5 | import org.springframework.data.jpa.domain.Specification 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor 7 | import org.springframework.data.repository.CrudRepository 8 | 9 | /** 10 | * Spring Data JPA for Process definitions. 11 | */ 12 | interface ProcessDefinitionRepository : CrudRepository, JpaSpecificationExecutor { 13 | companion object { 14 | 15 | /** 16 | * Specification for checking authorization of multiple principals. 17 | */ 18 | fun isStarterAuthorizedFor(principals: Collection): Specification = 19 | composeOr(principals.map { principal -> 20 | Specification { processDefinition, _, builder -> 21 | builder.isMember( 22 | "${principal.type}:${principal.name}", 23 | processDefinition.get>(ProcessDefinitionEntity::authorizedStarterPrincipals.name) 24 | ) 25 | } 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/process/ProcessInstanceRepository.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.process 2 | 3 | import io.holunda.polyflow.view.ProcessInstanceState 4 | import io.holunda.polyflow.view.jpa.composeOr 5 | import org.springframework.data.jpa.domain.Specification 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor 7 | import org.springframework.data.repository.CrudRepository 8 | 9 | /** 10 | * Repository for process instances. 11 | */ 12 | interface ProcessInstanceRepository : CrudRepository, JpaSpecificationExecutor { 13 | 14 | companion object { 15 | /** 16 | * Checks if the instance has one of provided states. 17 | */ 18 | fun hasStates(processInstanceStates: Set): Specification = 19 | composeOr(processInstanceStates.map { state -> 20 | Specification { instance, _, builder -> 21 | builder.equal( 22 | instance.get(ProcessInstanceEntity::state.name), 23 | state 24 | ) 25 | } 26 | }) 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /view/jpa/src/main/kotlin/io/holunda/polyflow/view/jpa/task/TaskAndDataEntryPayloadAttributeEntity.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.task 2 | 3 | import jakarta.persistence.EmbeddedId 4 | import jakarta.persistence.Entity 5 | import jakarta.persistence.Table 6 | 7 | @Entity 8 | @Table(name = "PLF_VIEW_TASK_AND_DATA_ENTRY_PAYLOAD") 9 | class TaskAndDataEntryPayloadAttributeEntity( 10 | @EmbeddedId 11 | var id: TaskAndDataEntryPayloadAttributeEntityId 12 | ) { 13 | constructor(taskId: String, path: String, value: String) : this( 14 | TaskAndDataEntryPayloadAttributeEntityId( 15 | taskId, 16 | path, 17 | value 18 | ) 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /view/jpa/src/sql/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | io.holunda.polyflow.view.jpa.data.DataEntryEntity 14 | io.holunda.polyflow.view.jpa.data.ProtocolElement 15 | io.holunda.polyflow.view.jpa.process.ProcessDefinitionEntity 16 | io.holunda.polyflow.view.jpa.process.ProcessInstanceEntity 17 | io.holunda.polyflow.view.jpa.task.TaskEntity 18 | 19 | 20 | -------------------------------------------------------------------------------- /view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/data/DataEntryIdTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.data 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.assertj.core.api.Assertions.assertThatThrownBy 5 | import org.junit.jupiter.api.Test 6 | 7 | internal class DataEntryIdTest { 8 | 9 | @Test 10 | fun `should construct data entry id `() { 11 | val id = DataEntryId("type:id") 12 | assertThat(id).isEqualTo(DataEntryId(entryType = "type", entryId = "id")) 13 | } 14 | 15 | @Test 16 | fun `should construct data entry id with id containing a colon`() { 17 | val id = DataEntryId("type:id:k") 18 | assertThat(id).isEqualTo(DataEntryId(entryType = "type", entryId = "id:k")) 19 | } 20 | 21 | 22 | @Test 23 | fun `should not construct data entry id`() { 24 | assertThatThrownBy { DataEntryId("bad string") }.hasMessage("Illegal identity format, expecting :, received 'bad string'") 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/itest/FixedH2Dialect.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.itest 2 | 3 | import org.hibernate.boot.model.TypeContributions 4 | import org.hibernate.dialect.H2Dialect 5 | import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo 6 | import org.hibernate.service.ServiceRegistry 7 | import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl 8 | import java.sql.Types 9 | 10 | @Suppress("unused") // used in application-itest.yaml 11 | class FixedH2Dialect(info: DialectResolutionInfo) : H2Dialect(info) { 12 | override fun registerColumnTypes(typeContributions: TypeContributions, serviceRegistry: ServiceRegistry) { 13 | super.registerColumnTypes(typeContributions, serviceRegistry) 14 | val ddlTypeRegistry = typeContributions.typeConfiguration.ddlTypeRegistry 15 | ddlTypeRegistry.addDescriptor(DdlTypeImpl(Types.BLOB, "bytea", this)) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/itest/MockQueryEmitterConfiguration.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.itest 2 | 3 | import org.axonframework.queryhandling.QueryUpdateEmitter 4 | import org.mockito.Mockito 5 | import org.springframework.context.annotation.Bean 6 | import org.springframework.context.annotation.Configuration 7 | import org.springframework.context.annotation.Primary 8 | import org.springframework.context.annotation.Profile 9 | 10 | @Configuration 11 | @Profile("mock-query-emitter") 12 | class MockQueryEmitterConfiguration { 13 | 14 | @Bean 15 | @Primary 16 | fun mockingQueryUpdateEmitter(): QueryUpdateEmitter = Mockito.mock(QueryUpdateEmitter::class.java) 17 | } 18 | -------------------------------------------------------------------------------- /view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/itest/ObjectMapperConfiguration.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.itest 2 | 3 | import com.fasterxml.jackson.databind.SerializationFeature 4 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule 5 | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper 6 | import org.springframework.context.annotation.Bean 7 | import org.springframework.context.annotation.Configuration 8 | import java.text.SimpleDateFormat 9 | 10 | @Configuration 11 | class ObjectMapperConfiguration { 12 | @Bean 13 | fun objectMapper() = jacksonObjectMapper().apply { 14 | dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'") 15 | registerModule(JavaTimeModule()) 16 | configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) 17 | configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/itest/TestApplicationDataJpa.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.itest 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.context.annotation.ComponentScan 5 | import org.springframework.context.annotation.Import 6 | 7 | @SpringBootApplication 8 | @Import(value = [ObjectMapperConfiguration::class, MockQueryEmitterConfiguration::class]) 9 | @ComponentScan(basePackages = ["io.holunda.polyflow.view.jpa"]) 10 | class TestApplicationDataJpa 11 | -------------------------------------------------------------------------------- /view/jpa/src/test/kotlin/io/holunda/polyflow/view/jpa/task/TaskEntityTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.jpa.task 2 | 3 | import io.holunda.polyflow.view.jpa.emptyTask 4 | import org.assertj.core.api.Assertions.assertThat 5 | import org.junit.jupiter.api.Test 6 | import java.time.Instant 7 | 8 | internal class TaskEntityTest { 9 | 10 | @Test 11 | fun `test toString`() { 12 | val now = Instant.now() 13 | val task = emptyTask().apply { 14 | taskId = "id-123" 15 | taskDefinitionKey = "def-098" 16 | name = "name" 17 | createdDate = now 18 | } 19 | assertThat(task.toString()).isEqualTo("Task[taskId=id-123, taskDefinitionKey=def-098, name=name, created=$now]") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/application-itest-tc-mariadb.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | jpa: 3 | open-in-view: true # disable JPA warning 4 | show-sql: false 5 | database-platform: org.hibernate.dialect.MariaDBDialect 6 | generate-ddl: false 7 | hibernate.ddl-auto: none 8 | datasource: 9 | url: jdbc:tc:mariadb:10.11:///testDb 10 | username: sa 11 | password: sa 12 | flyway: 13 | enabled: true 14 | locations: "classpath:db/migrations/mariadb" 15 | 16 | polyflow: 17 | view: 18 | jpa: 19 | stored-items: TASK, DATA_ENTRY, PROCESS_INSTANCE, PROCESS_DEFINITION 20 | 21 | logging: 22 | level: 23 | root: INFO 24 | org.springframework: INFO 25 | org.axonframework: INFO 26 | org.hibernate.type: INFO # activate this and generic ROOT logger to see SQL and binding 27 | io.holixon.axon.gateway.query: INFO 28 | io.holunda.polyflow.view.jpa: INFO 29 | 30 | axon: 31 | axonserver: 32 | enabled: false 33 | eventhandling: 34 | processors: 35 | [io.holunda.polyflow.view.jpa.service.data]: 36 | mode: subscribing 37 | source: eventBus 38 | 39 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | =============================================================================== 2 | JPA View I-Test, using SpringBoot ${spring-boot.formatted-version} 3 | =============================================================================== 4 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/h2-postgresql/V0_0_10__axon_sequences_per_table.sql: -------------------------------------------------------------------------------- 1 | DROP SEQUENCE hibernate_sequence; 2 | 3 | CREATE SEQUENCE association_value_entry_seq START WITH 1 INCREMENT BY 50; 4 | 5 | CREATE SEQUENCE domain_event_entry_seq START WITH 1 INCREMENT BY 50; 6 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/h2-postgresql/V0_0_11__jpa_view_correlation_payload.sql: -------------------------------------------------------------------------------- 1 | create view PLF_VIEW_TASK_AND_DATA_ENTRY_PAYLOAD as 2 | ((select pc.TASK_ID, dea.PATH, dea.VALUE 3 | from PLF_TASK_CORRELATIONS pc 4 | join PLF_DATA_ENTRY_PAYLOAD_ATTRIBUTES dea on pc.ENTRY_ID = dea.ENTRY_ID and pc.ENTRY_TYPE = dea.ENTRY_TYPE) 5 | union 6 | select * from PLF_TASK_PAYLOAD_ATTRIBUTES); 7 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/h2-postgresql/V0_0_12__jpa_plf_data_entry_correlations.sql: -------------------------------------------------------------------------------- 1 | create table PLF_DATA_ENTRY_CORRELATIONS 2 | ( 3 | OWNING_ENTRY_TYPE varchar(255) not null, 4 | OWNING_ENTRY_ID varchar(64) not null, 5 | ENTRY_TYPE varchar(255) not null, 6 | ENTRY_ID varchar(64) not null, 7 | primary key (OWNING_ENTRY_TYPE, OWNING_ENTRY_ID, ENTRY_TYPE, ENTRY_ID) 8 | ); 9 | 10 | create view PLF_VIEW_DATA_ENTRY_PAYLOAD as 11 | ( 12 | select * 13 | from PLF_DATA_ENTRY_PAYLOAD_ATTRIBUTES 14 | union 15 | (select ec.OWNING_ENTRY_ID as ENTRY_ID, 16 | ec.OWNING_ENTRY_TYPE as ENTRY_TYPE, 17 | ep.path as PATH, 18 | ep.value as VALUE 19 | from PLF_DATA_ENTRY_CORRELATIONS ec 20 | join PLF_DATA_ENTRY_PAYLOAD_ATTRIBUTES ep 21 | on 22 | ec.ENTRY_ID = ep.ENTRY_ID and ec.ENTRY_TYPE = ep.ENTRY_TYPE) 23 | ); 24 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/h2-postgresql/V0_0_4__tasklist_filters.sql: -------------------------------------------------------------------------------- 1 | -- All tasks excludes just for admin 2 | INSERT INTO ACT_RU_FILTER (ID_, REV_, RESOURCE_TYPE_, NAME_, OWNER_, QUERY_, PROPERTIES_) 3 | VALUES ('F000', 1, 'Task', 'All Tasks', 'admin', '{}', 4 | '{"showUndefinedVariable":false,"description":"All tasks (for admin use only!)","refresh":true,"priority":0}'); 5 | 6 | INSERT INTO ACT_RU_AUTHORIZATION (ID_, REV_, TYPE_, GROUP_ID_, USER_ID_, RESOURCE_TYPE_, RESOURCE_ID_, PERMS_) 7 | VALUES ('A20', 1, 1, null, 'admin', 5, 'F000', 2147483647); 8 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/h2-postgresql/V0_0_6__request.sql: -------------------------------------------------------------------------------- 1 | create table APP_APPROVAL_REQUEST 2 | ( 3 | id varchar(255) not null, 4 | amount decimal(10, 2), 5 | applicant varchar(255), 6 | currency varchar(255), 7 | subject varchar(255), 8 | primary key (id) 9 | ); 10 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/h2-postgresql/V0_0_8__axon_dlq.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE dead_letter_entry 2 | ( 3 | dead_letter_id VARCHAR(255) NOT NULL, 4 | cause_message VARCHAR(255), 5 | cause_type VARCHAR(255), 6 | diagnostics BYTEA, 7 | enqueued_at TIMESTAMP NOT NULL, 8 | last_touched TIMESTAMP, 9 | aggregate_identifier VARCHAR(255), 10 | event_identifier VARCHAR(255) NOT NULL, 11 | message_type VARCHAR(255) NOT NULL, 12 | meta_data BYTEA, 13 | payload BYTEA NOT NULL, 14 | payload_revision VARCHAR(255), 15 | payload_type VARCHAR(255) NOT NULL, 16 | sequence_number INT8, 17 | time_stamp VARCHAR(255) NOT NULL, 18 | token BYTEA, 19 | token_type VARCHAR(255), 20 | type VARCHAR(255), 21 | processing_group VARCHAR(255) NOT NULL, 22 | processing_started TIMESTAMP, 23 | sequence_identifier VARCHAR(255) NOT NULL, 24 | sequence_index INT8 NOT NULL, 25 | PRIMARY KEY (dead_letter_id) 26 | ); 27 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/h2-postgresql/V0_0_9__polyflow_deleted.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE plf_data_entry 2 | ADD date_deleted timestamp; 3 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/mariadb/V0_0_10__jpa_view_correlation_payload.sql: -------------------------------------------------------------------------------- 1 | create view plf_view_task_and_data_entry_payload as 2 | ((select pc.task_id, dea.path, dea.value 3 | from plf_task_correlations pc 4 | join plf_data_entry_payload_attributes dea on pc.entry_id = dea.entry_id and pc.entry_type = dea.entry_type) 5 | union 6 | select * from plf_task_payload_attributes); 7 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/mariadb/V0_0_11__jpa_plf_data_entry_correlations.sql: -------------------------------------------------------------------------------- 1 | create table plf_data_entry_correlations 2 | ( 3 | owning_entry_type varchar(255) not null, 4 | owning_entry_id varchar(64) not null, 5 | entry_type varchar(255) not null, 6 | entry_id varchar(64) not null, 7 | primary key (owning_entry_type, owning_entry_id, entry_type, entry_id) 8 | ); 9 | 10 | create view plf_view_data_entry_payload as 11 | ( 12 | select * 13 | from plf_data_entry_payload_attributes 14 | union 15 | (select ec.owning_entry_id as ENTRY_ID, 16 | ec.owning_entry_type as ENTRY_TYPE, 17 | ep.path as PATH, 18 | ep.value as VALUE 19 | from plf_data_entry_correlations ec 20 | join plf_data_entry_payload_attributes ep 21 | on 22 | ec.entry_id = ep.entry_id and ec.entry_type = ep.entry_type) 23 | ); 24 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/mariadb/V0_0_4__tasklist_filters.sql: -------------------------------------------------------------------------------- 1 | -- All tasks excludes just for admin 2 | INSERT INTO ACT_RU_FILTER (ID_, REV_, RESOURCE_TYPE_, NAME_, OWNER_, QUERY_, PROPERTIES_) 3 | VALUES ('F000', 1, 'Task', 'All Tasks', 'admin', '{}', 4 | '{"showUndefinedVariable":false,"description":"All tasks (for admin use only!)","refresh":true,"priority":0}'); 5 | 6 | INSERT INTO ACT_RU_AUTHORIZATION (ID_, REV_, TYPE_, GROUP_ID_, USER_ID_, RESOURCE_TYPE_, RESOURCE_ID_, PERMS_) 7 | VALUES ('A20', 1, 1, null, 'admin', 5, 'F000', 2147483647); 8 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/mariadb/V0_0_6__request.sql: -------------------------------------------------------------------------------- 1 | create table APP_APPROVAL_REQUEST 2 | ( 3 | id varchar(255) not null, 4 | amount decimal(10, 2), 5 | applicant varchar(255), 6 | currency varchar(255), 7 | subject varchar(255), 8 | primary key (id) 9 | ); 10 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/mariadb/V0_0_8__axon_dlq.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE dead_letter_entry 2 | ( 3 | dead_letter_id VARCHAR(255) NOT NULL, 4 | cause_message VARCHAR(255), 5 | cause_type VARCHAR(255), 6 | diagnostics LONGBLOB, 7 | enqueued_at TIMESTAMP NOT NULL, 8 | last_touched TIMESTAMP, 9 | aggregate_identifier VARCHAR(255), 10 | event_identifier VARCHAR(255) NOT NULL, 11 | message_type VARCHAR(255) NOT NULL, 12 | meta_data LONGBLOB, 13 | payload LONGBLOB NOT NULL, 14 | payload_revision VARCHAR(255), 15 | payload_type VARCHAR(255) NOT NULL, 16 | sequence_number INT8, 17 | time_stamp VARCHAR(255) NOT NULL, 18 | token LONGBLOB, 19 | token_type VARCHAR(255), 20 | type VARCHAR(255), 21 | processing_group VARCHAR(255) NOT NULL, 22 | processing_started TIMESTAMP, 23 | sequence_identifier VARCHAR(255) NOT NULL, 24 | sequence_index INT8 NOT NULL, 25 | PRIMARY KEY (dead_letter_id) 26 | ); 27 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/db/migrations/mariadb/V0_0_9__axon_sequences_per_table.sql: -------------------------------------------------------------------------------- 1 | DROP SEQUENCE hibernate_sequence; 2 | 3 | CREATE SEQUENCE association_value_entry_seq START WITH 1 INCREMENT BY 50; 4 | 5 | CREATE SEQUENCE domain_event_entry_seq START WITH 1 INCREMENT BY 50; 6 | -------------------------------------------------------------------------------- /view/jpa/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/ChangeStreamOptionsSupport.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo 2 | 3 | import com.mongodb.client.model.changestream.OperationType 4 | import org.bson.BsonValue 5 | import org.springframework.data.mongodb.core.ChangeStreamOptions 6 | import org.springframework.data.mongodb.core.aggregation.Aggregation 7 | import org.springframework.data.mongodb.core.query.Criteria 8 | 9 | /** 10 | * Create change stream options, compatible with Cosmos DB. 11 | * Includes resume token, if it is not null. 12 | */ 13 | fun BsonValue?.changeStreamOptions(): ChangeStreamOptions { 14 | return ChangeStreamOptions 15 | .builder() 16 | .filter( 17 | Aggregation.newAggregation( 18 | Aggregation.match(Criteria.where("operationType").`in`(OperationType.INSERT.value, OperationType.UPDATE.value, OperationType.REPLACE.value)), 19 | Aggregation.project("fullDocument") 20 | ) 21 | ).let { builder -> 22 | if (this != null) { 23 | builder.resumeToken(this) 24 | } else { 25 | builder 26 | } 27 | }.build() 28 | } 29 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/EnableTaskPoolMongoView.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo 2 | 3 | import org.springframework.context.annotation.Import 4 | 5 | /** 6 | * Enables polyflow projection using Mongo DB as persistence. 7 | */ 8 | @MustBeDocumented 9 | @Deprecated(message = "Please use EnablePolyflowMongoView instead", replaceWith = ReplaceWith("EnablePolyflowMongoView")) 10 | @Import(TaskPoolMongoViewConfiguration::class) 11 | annotation class EnableTaskPoolMongoView 12 | 13 | /** 14 | * Enables polyflow projection using Mongo DB as persistence. 15 | */ 16 | @MustBeDocumented 17 | @Import(TaskPoolMongoViewConfiguration::class) 18 | annotation class EnablePolyflowMongoView 19 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/data/DataEntryUpdateRepository.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo.data 2 | 3 | import org.bson.BsonValue 4 | import org.springframework.data.mongodb.core.ChangeStreamEvent 5 | import reactor.core.publisher.Flux 6 | 7 | /** 8 | * Repository for retrieving change updates. 9 | */ 10 | interface DataEntryUpdateRepository { 11 | /** 12 | * Retrieves change stream of data entry updates. 13 | * @param resumeToken resume token showing current position. 14 | * @return change event stream. 15 | */ 16 | fun getDataEntryUpdates(resumeToken: BsonValue?): Flux> 17 | } 18 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/data/DataEntryUpdateRepositoryImpl.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo.data 2 | 3 | import io.holunda.polyflow.view.mongo.changeStreamOptions 4 | import org.bson.BsonValue 5 | import org.springframework.data.mongodb.core.ChangeStreamEvent 6 | import org.springframework.data.mongodb.core.ReactiveMongoTemplate 7 | import reactor.core.publisher.Flux 8 | 9 | /** 10 | * Implementation of the change stream based on Mongo template. 11 | */ 12 | open class DataEntryUpdateRepositoryImpl( 13 | private val mongoTemplate: ReactiveMongoTemplate 14 | ) : DataEntryUpdateRepository { 15 | override fun getDataEntryUpdates(resumeToken: BsonValue?): Flux> { 16 | return mongoTemplate.changeStream(DataEntryDocument.COLLECTION, resumeToken.changeStreamOptions(), DataEntryDocument::class.java) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/process/ProcessDefinitionRepository.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo.process 2 | 3 | import org.springframework.data.mongodb.repository.Query 4 | import org.springframework.data.mongodb.repository.ReactiveMongoRepository 5 | import org.springframework.data.repository.query.Param 6 | import org.springframework.stereotype.Repository 7 | import reactor.core.publisher.Flux 8 | 9 | 10 | /** 11 | * Repository for process definitions. 12 | */ 13 | @Repository 14 | interface ProcessDefinitionRepository : ReactiveMongoRepository { 15 | 16 | /** 17 | * Find all for given user. 18 | */ 19 | @Query("{ \$or: [ { 'candidateStarterUsers' : ?0 }, { 'candidateStarterGroups' : ?1} ] }") 20 | fun findAllForUser(@Param("username") username: String, @Param("groupNames") groupNames: Set): Flux 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/task/TaskCountByApplicationRepositoryExtension.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo.task 2 | 3 | import io.holunda.polyflow.view.query.task.ApplicationWithTaskCount 4 | import reactor.core.publisher.Flux 5 | import reactor.core.publisher.Mono 6 | 7 | /** 8 | * Counts tasks. 9 | */ 10 | interface TaskCountByApplicationRepositoryExtension { 11 | /** 12 | * Retrieves counts grouped by application names. 13 | */ 14 | fun findTaskCountsByApplication(): Flux 15 | 16 | /** 17 | * Retrieves a count of tasks for given application. 18 | */ 19 | fun findTaskCountForApplication(applicationName: String): Mono 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/task/TaskRepositoryExtension.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo.task 2 | 3 | import org.springframework.data.domain.Pageable 4 | import reactor.core.publisher.Flux 5 | 6 | /** 7 | * Extension to allow single type for implementation. 8 | */ 9 | interface TaskRepositoryExtension : TaskCountByApplicationRepositoryExtension, TaskUpdatesExtension { 10 | /** 11 | * Find tasks visible to the user or one of the groups, optionally restricted by business key and priority. 12 | * 13 | * @param username user's name 14 | * @param groupNames user's groups 15 | * @param businessKey Business Key to restrict. 16 | * @param priorities Priorities to restrict. 17 | * If non-null and non-empty, any of the contained priorities must match. 18 | * @param pageable defines sorting and paging requirements. 19 | * @return Flux of matching documents. 20 | */ 21 | fun findForUser( 22 | username: String, 23 | groupNames: Collection, 24 | businessKey: String?, 25 | priorities: Collection?, 26 | pageable: Pageable? 27 | ): Flux 28 | } 29 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/task/TaskUpdatesExtension.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo.task 2 | 3 | import org.bson.BsonValue 4 | import org.springframework.data.mongodb.core.ChangeStreamEvent 5 | import reactor.core.publisher.Flux 6 | 7 | /** 8 | * Task updates. 9 | */ 10 | interface TaskUpdatesExtension { 11 | /** 12 | * Retrieves a task updates flux. 13 | */ 14 | fun getTaskUpdates(resumeToken: BsonValue? = null): Flux> 15 | } 16 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/task/TaskWithDataEntriesRepository.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo.task 2 | 3 | import org.springframework.data.mongodb.repository.ReactiveMongoRepository 4 | import org.springframework.stereotype.Repository 5 | 6 | 7 | /** 8 | * Reactive mongo repository for tasks with data entries. 9 | */ 10 | @Repository 11 | interface TaskWithDataEntriesRepository : TaskWithDataEntriesRepositoryExtension, ReactiveMongoRepository 12 | 13 | -------------------------------------------------------------------------------- /view/mongo/src/main/kotlin/io/holunda/polyflow/view/mongo/task/TaskWithDataEntriesRepositoryExtension.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.mongo.task 2 | 3 | import io.holunda.polyflow.view.auth.User 4 | import io.holunda.polyflow.view.filter.Criterion 5 | import org.springframework.data.domain.Pageable 6 | import reactor.core.publisher.Flux 7 | 8 | 9 | /** 10 | * Repository extension. 11 | */ 12 | interface TaskWithDataEntriesRepositoryExtension { 13 | 14 | /** 15 | * Find all tasks with data entries matching specified filter. 16 | */ 17 | fun findAllFilteredForUser(user: User, criteria: List, pageable: Pageable? = null): Flux 18 | } 19 | -------------------------------------------------------------------------------- /view/mongo/src/test/resources/application-itest-replicated.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | data: 3 | mongodb: 4 | uri: mongodb://127.0.0.1:27017/?replicaSet=repembedded 5 | -------------------------------------------------------------------------------- /view/mongo/src/test/resources/application-itest-standalone.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | data: 3 | mongodb: 4 | uri: mongodb://127.0.0.1:27017 5 | -------------------------------------------------------------------------------- /view/mongo/src/test/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | Mongo ITEST 3 | ------------------------------------------------------------------------------- 4 | -------------------------------------------------------------------------------- /view/mongo/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /view/simple/src/main/kotlin/io/holunda/polyflow/view/simple/EnablePolyflowSimpleView.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.simple 2 | 3 | import org.springframework.context.annotation.Import 4 | 5 | 6 | /** 7 | * Enables simple (in-memory) polyflow view. 8 | */ 9 | @MustBeDocumented 10 | @Import(TaskPoolSimpleViewConfiguration::class) 11 | annotation class EnablePolyflowSimpleView 12 | -------------------------------------------------------------------------------- /view/simple/src/main/kotlin/io/holunda/polyflow/view/simple/service/SimpleServiceViewProcessingGroup.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.simple.service 2 | 3 | import io.github.oshai.kotlinlogging.KotlinLogging 4 | import org.axonframework.config.EventProcessingConfiguration 5 | import org.axonframework.eventhandling.TrackingEventProcessor 6 | import org.springframework.stereotype.Component 7 | 8 | private val logger = KotlinLogging.logger {} 9 | 10 | /** 11 | * Component responsible for offering replay functionality of the processor. 12 | */ 13 | @Component 14 | class SimpleServiceViewProcessingGroup( 15 | private val configuration: EventProcessingConfiguration 16 | ) { 17 | 18 | companion object { 19 | const val PROCESSING_GROUP = "io.holunda.polyflow.view.simple" 20 | } 21 | 22 | /** 23 | * Configure to run a event replay to fill the simple task view with events on start-up. 24 | */ 25 | fun restore() { 26 | this.configuration 27 | .eventProcessorByProcessingGroup(PROCESSING_GROUP, TrackingEventProcessor::class.java) 28 | .ifPresent { 29 | logger.info { "VIEW-SIMPLE-002: Starting simple view event replay." } 30 | it.shutDown() 31 | it.resetTokens() 32 | it.start() 33 | } 34 | } 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /view/simple/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /view/view-api-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | io.holunda.polyflow 8 | polyflow-view-parent 9 | 4.4.1-SNAPSHOT 10 | 11 | 12 | polyflow-view-api-client 13 | core/view/${project.artifactId} 14 | 15 | 16 | 17 | io.holunda.polyflow 18 | polyflow-view-api 19 | 20 | 21 | 22 | 23 | 24 | 25 | org.apache.maven.plugins 26 | maven-surefire-plugin 27 | 28 | false 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /view/view-api-client/src/main/kotlin/ProcessDefinitionQueryClient.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view 2 | 3 | import io.holunda.polyflow.view.query.process.ProcessDefinitionsStartableByUserQuery 4 | import io.holunda.polyflow.view.query.task.* 5 | import org.axonframework.messaging.responsetypes.ResponseTypes 6 | import org.axonframework.queryhandling.QueryGateway 7 | import java.util.concurrent.CompletableFuture 8 | 9 | /** 10 | * Client encapsulating the correct query types (including response types) 11 | */ 12 | open class ProcessDefinitionQueryClient( 13 | private val queryGateway: QueryGateway 14 | ) { 15 | 16 | /** 17 | * @see io.holunda.polyflow.view.query.process.ProcessDefinitionApi.query 18 | * @see io.holunda.polyflow.view.query.process.ProcessDefinitionsStartableByUserQuery 19 | */ 20 | fun query(query: ProcessDefinitionsStartableByUserQuery): CompletableFuture> = 21 | queryGateway.query( 22 | query, 23 | ResponseTypes.multipleInstancesOf(ProcessDefinition::class.java) 24 | ) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /view/view-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | io.holunda.polyflow 8 | polyflow-view-parent 9 | 4.4.1-SNAPSHOT 10 | 11 | 12 | polyflow-view-api 13 | core/view/${project.artifactId} 14 | 15 | 16 | 17 | io.holunda.polyflow 18 | polyflow-taskpool-event 19 | 20 | 21 | io.holunda.polyflow 22 | polyflow-datapool-event 23 | 24 | 25 | io.holixon.axon.gateway 26 | axon-gateway-extension 27 | 28 | 29 | org.springframework 30 | spring-core 31 | provided 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/ComponentLike.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view 2 | 3 | /** 4 | * Marker annotation to open the classes in Kotlin. 5 | */ 6 | @MustBeDocumented 7 | @Target(AnnotationTarget.CLASS, AnnotationTarget.ANNOTATION_CLASS) 8 | annotation class ComponentLike 9 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/FormUrlResolver.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view 2 | 3 | /** 4 | * Facility to resolve URLs of forms. 5 | */ 6 | interface FormUrlResolver { 7 | /** 8 | * Creates a complete URL to call the tasks form e.g. from the task list 9 | */ 10 | fun resolveUrl(task: Task): String 11 | /** 12 | * Creates a complete URL to call the start forms. 13 | */ 14 | fun resolveUrl(processDefinition: ProcessDefinition): String 15 | /** 16 | * Creates a complete 17 | */ 18 | fun resolveUrl(dataEntry: DataEntry): String 19 | } 20 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/ProcessDefinition.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view 2 | 3 | /** 4 | * Represents a deployed process definition. 5 | */ 6 | data class ProcessDefinition( 7 | val processDefinitionId: String, 8 | val processDefinitionKey: String, 9 | val processDefinitionVersion: Int, 10 | 11 | val applicationName: String, 12 | val processName: String, 13 | val processVersionTag: String? = null, 14 | val processDescription: String? = null, 15 | val formKey: String? = null, 16 | val startableFromTasklist: Boolean = true, 17 | val candidateStarterUsers: Set = setOf(), 18 | val candidateStarterGroups: Set = setOf() 19 | ) 20 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/ProcessInstanceState.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view 2 | 3 | /** 4 | * Process instance state. 5 | */ 6 | enum class ProcessInstanceState { 7 | /** 8 | * Process is running. 9 | */ 10 | RUNNING, 11 | 12 | /** 13 | * Process is finished. 14 | */ 15 | FINISHED, 16 | 17 | /** 18 | * Process is cancelled. 19 | */ 20 | CANCELLED, 21 | 22 | /** 23 | * Process is suspended. 24 | */ 25 | SUSPENDED 26 | } 27 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/ProcessVariable.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view 2 | 3 | import io.holunda.camunda.taskpool.api.process.variable.ProcessVariableValue 4 | import io.holunda.camunda.taskpool.api.task.SourceReference 5 | 6 | /** 7 | * Represents a process variable. 8 | */ 9 | data class ProcessVariable( 10 | val variableName: String, 11 | val variableInstanceId: String, 12 | val sourceReference: SourceReference, 13 | val scopeActivityInstanceId: String, 14 | val value: ProcessVariableValue 15 | ) 16 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/ProtocolEntry.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view 2 | 3 | import io.holunda.camunda.taskpool.api.business.DataEntryState 4 | import java.time.Instant 5 | import java.util.* 6 | 7 | /** 8 | * Represents a protocol entry. 9 | */ 10 | data class ProtocolEntry( 11 | val time: Instant, 12 | val state: DataEntryState, 13 | val username: String?, 14 | val logMessage: String?, 15 | val logDetails: String? 16 | ) 17 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/auth/User.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.auth 2 | 3 | /** 4 | * Simple user abstraction. 5 | * @param username username of the user. 6 | * @param groups set of group names assigned to the user. 7 | */ 8 | data class User( 9 | val username: String, 10 | val groups: Set 11 | ) 12 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/auth/UserService.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.auth 2 | 3 | /** 4 | * Simple integration hook into auth of the final system. 5 | */ 6 | interface UserService { 7 | 8 | /** 9 | * Retrieves a user for given user identifier. 10 | * [userIdentifier] a token or a key identifying the user. 11 | * @return User 12 | * @throws UnknownUserException if user not found. 13 | */ 14 | @Throws(UnknownUserException::class) 15 | fun getUser(userIdentifier: String): User 16 | 17 | } 18 | 19 | /** 20 | * Is thrown if the user is not known in the system. 21 | */ 22 | class UnknownUserException(reason: String) : IllegalArgumentException(reason) 23 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/FilterQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query 2 | 3 | /** 4 | * Query using a filter function. 5 | */ 6 | interface FilterQuery { 7 | /** 8 | * Applies the filter. 9 | * @param element element to check. 10 | * @return true, if the element is included into the result. 11 | */ 12 | fun applyFilter(element: T): Boolean 13 | } 14 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/data/DataEntriesForDataEntryTypeQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.data 2 | 3 | import io.holunda.camunda.taskpool.api.business.EntryType 4 | import io.holunda.polyflow.view.DataEntry 5 | import io.holunda.polyflow.view.query.FilterQuery 6 | import io.holunda.polyflow.view.query.PageableSortableQuery 7 | 8 | /** 9 | * Query by entry type. 10 | * @param entryType type of data entry. 11 | * @param page current page, zero-based index. 12 | * @param size page size 13 | */ 14 | data class DataEntriesForDataEntryTypeQuery( 15 | val entryType: EntryType, 16 | override val page: Int = 0, 17 | override val size: Int = Int.MAX_VALUE, 18 | override val sort: List = listOf() 19 | ) : FilterQuery, PageableSortableQuery { 20 | 21 | @Deprecated("Please use other constructor setting sort as List") 22 | constructor(entryType: EntryType, page: Int = 0, size: Int = Int.MAX_VALUE, sort: String?) : this( 23 | entryType = entryType, 24 | page = page, 25 | size = size, 26 | sort = if (sort.isNullOrBlank()) { 27 | listOf() 28 | } else { 29 | listOf(sort) 30 | }, 31 | ) 32 | 33 | override fun applyFilter(element: DataEntry) = element.entryType == this.entryType 34 | } 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/data/DataEntriesQueryResult.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.data 2 | 3 | import io.holunda.polyflow.view.DataEntry 4 | import io.holunda.polyflow.view.query.PageableSortableQuery 5 | import io.holunda.polyflow.view.query.QueryResult 6 | 7 | /** 8 | * Results of a query for multiple data entries. 9 | */ 10 | data class DataEntriesQueryResult( 11 | override val elements: List, 12 | override val totalElementCount: Int = elements.size 13 | ) : QueryResult(elements = elements, totalElementCount = totalElementCount) { 14 | 15 | override fun slice(query: PageableSortableQuery) = this.copy(elements = super.slice(query).elements) 16 | } 17 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/data/DataEntryForIdentityQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.data 2 | 3 | import io.holunda.camunda.taskpool.api.business.DataIdentity 4 | import io.holunda.camunda.taskpool.api.business.EntryId 5 | import io.holunda.camunda.taskpool.api.business.EntryType 6 | import io.holunda.polyflow.view.DataEntry 7 | import io.holunda.polyflow.view.query.FilterQuery 8 | 9 | /** 10 | * Query for entry type and optional id. 11 | * @param entryType type of the data entry. 12 | * @param entryId id of the data entry. 13 | */ 14 | data class DataEntryForIdentityQuery( 15 | val entryType: EntryType, 16 | val entryId: EntryId, 17 | ) : FilterQuery { 18 | 19 | /** 20 | * Additional convenience constructor. 21 | */ 22 | constructor( 23 | identity: DataIdentity 24 | ) : this( 25 | entryType = identity.entryType, 26 | entryId = identity.entryId, 27 | ) 28 | 29 | override fun applyFilter(element: DataEntry) = element.entryType == this.entryType && element.entryId == this.entryId 30 | } 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/data/QueryDataIdentity.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.data 2 | 3 | import io.holunda.camunda.taskpool.api.business.DataIdentity 4 | import io.holunda.camunda.taskpool.api.business.EntryId 5 | import io.holunda.camunda.taskpool.api.business.EntryType 6 | 7 | /** 8 | * Identity used in queries. 9 | */ 10 | data class QueryDataIdentity( 11 | override val entryType: EntryType, 12 | override val entryId: EntryId 13 | ) : DataIdentity 14 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/ProcessDefinitionApi.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process 2 | 3 | import io.holunda.polyflow.view.ProcessDefinition 4 | 5 | /** 6 | * Queries for process definitions. 7 | */ 8 | interface ProcessDefinitionApi { 9 | 10 | /** 11 | * Query for process definitions startable by user. 12 | * @param query query object. 13 | * @return list of process definitions. 14 | */ 15 | fun query(query: ProcessDefinitionsStartableByUserQuery): List 16 | } 17 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/ProcessDefinitionsStartableByUserQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process 2 | 3 | import io.holunda.polyflow.view.ProcessDefinition 4 | import io.holunda.polyflow.view.auth.User 5 | import io.holunda.polyflow.view.query.FilterQuery 6 | 7 | /** 8 | * Query for startable processes by given user. 9 | * @param user user with groups accessing the startable processes. 10 | */ 11 | data class ProcessDefinitionsStartableByUserQuery( 12 | val user: User 13 | ) : FilterQuery { 14 | 15 | override fun applyFilter(element: ProcessDefinition) = 16 | // start-able 17 | element.startableFromTasklist && 18 | // candidate user 19 | (element.candidateStarterUsers.contains(this.user.username) 20 | // candidate groups 21 | || (element.candidateStarterGroups.any { candidateGroup -> this.user.groups.contains(candidateGroup) })) 22 | } 23 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/ProcessInstanceApi.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process 2 | 3 | import org.axonframework.queryhandling.QueryResponseMessage 4 | 5 | /** 6 | * Process instance API. 7 | */ 8 | interface ProcessInstanceApi { 9 | 10 | /** 11 | * Query for process instances. 12 | * @param query query object. 13 | * @return list of process instances. 14 | */ 15 | fun query(query: ProcessInstancesByStateQuery): QueryResponseMessage 16 | } 17 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/ProcessInstanceQueryResult.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process 2 | 3 | import io.holunda.polyflow.view.ProcessInstance 4 | import io.holunda.polyflow.view.query.PageableSortableQuery 5 | import io.holunda.polyflow.view.query.QueryResult 6 | 7 | /** 8 | * Result for process instance queries. 9 | */ 10 | data class ProcessInstanceQueryResult( 11 | override val elements: List 12 | ) : QueryResult(elements = elements) { 13 | override fun slice(query: PageableSortableQuery) = this.copy(elements = super.slice(query).elements) 14 | } 15 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/ProcessInstancesByStateQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process 2 | 3 | import io.holunda.polyflow.view.ProcessInstance 4 | import io.holunda.polyflow.view.ProcessInstanceState 5 | import io.holunda.polyflow.view.query.FilterQuery 6 | 7 | /** 8 | * Query for process instance matching the provided states. 9 | */ 10 | data class ProcessInstancesByStateQuery( 11 | val states: Set 12 | ) : FilterQuery { 13 | override fun applyFilter(element: ProcessInstance): Boolean = states.contains(element = element.state) 14 | } 15 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/ReactiveProcessDefinitionApi.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process 2 | 3 | import io.holunda.polyflow.view.ProcessDefinition 4 | import org.axonframework.messaging.MetaData 5 | import java.util.concurrent.CompletableFuture 6 | 7 | /** 8 | * Reactive API for process definitions. 9 | * @see ProcessDefinitionApi 10 | * For the client, there is no difference in definition of the query, but the implementer has a different method to reflect the reactive nature. 11 | */ 12 | interface ReactiveProcessDefinitionApi { 13 | 14 | /** 15 | * Query for startable process definitions. 16 | * @param query query object. 17 | * @param metaData query metaData, may be empty. 18 | * @return observable list of process definitions. 19 | */ 20 | fun query(query: ProcessDefinitionsStartableByUserQuery, metaData: MetaData = MetaData.emptyInstance()): CompletableFuture> 21 | } 22 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/variable/ProcessVariableApi.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process.variable 2 | 3 | import org.axonframework.queryhandling.QueryResponseMessage 4 | 5 | /** 6 | * Process variable API. 7 | */ 8 | interface ProcessVariableApi { 9 | 10 | /** 11 | * Query for process variables. 12 | */ 13 | fun query(query: ProcessVariablesForInstanceQuery): QueryResponseMessage 14 | } 15 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/variable/ProcessVariableFilter.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process.variable 2 | 3 | import io.holunda.polyflow.view.ProcessVariable 4 | import java.util.function.Function 5 | 6 | /** 7 | * Process variable filter 8 | */ 9 | interface ProcessVariableFilter : Function { 10 | val type: ProcessVariableFilterType 11 | } 12 | 13 | /** 14 | * Filter type. 15 | */ 16 | enum class ProcessVariableFilterType { 17 | /** 18 | * Include variables. 19 | */ 20 | INCLUDE, 21 | 22 | /** 23 | * Exclude variables. 24 | */ 25 | EXCLUDE 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/variable/ProcessVariableQueryResult.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process.variable 2 | 3 | import io.holunda.polyflow.view.ProcessVariable 4 | 5 | /** 6 | * Response of the process variable query. 7 | */ 8 | data class ProcessVariableQueryResult( 9 | val variables: List 10 | ) 11 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/variable/ProcessVariablesForInstanceQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process.variable 2 | 3 | import io.holunda.polyflow.view.ProcessVariable 4 | import io.holunda.polyflow.view.query.FilterQuery 5 | 6 | /** 7 | * Query for variables of given process instance. 8 | * @param processInstanceId process instance id to query for. 9 | * @param variableFilter 10 | */ 11 | data class ProcessVariablesForInstanceQuery( 12 | val processInstanceId: String, 13 | val variableFilter: List 14 | ) : FilterQuery { 15 | 16 | override fun applyFilter(element: ProcessVariable): Boolean = 17 | element.sourceReference.instanceId == processInstanceId 18 | && (variableFilter.isEmpty() || variableFilter.any { filter -> filter.apply(element) }) 19 | 20 | } 21 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/variable/filter/ProcessVariableFilterExactlyOne.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process.variable.filter 2 | 3 | import io.holunda.polyflow.view.ProcessVariable 4 | import io.holunda.polyflow.view.query.process.variable.ProcessVariableFilter 5 | import io.holunda.polyflow.view.query.process.variable.ProcessVariableFilterType 6 | 7 | /** 8 | * Filter to query for exactly one variable. 9 | */ 10 | data class ProcessVariableFilterExactlyOne( 11 | val processVariableName: String 12 | ) : ProcessVariableFilter { 13 | 14 | override val type: ProcessVariableFilterType = ProcessVariableFilterType.INCLUDE 15 | override fun apply(variable: ProcessVariable): Boolean = processVariableName == variable.variableName 16 | } 17 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/process/variable/filter/ProcessVariableFilterOneOf.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process.variable.filter 2 | 3 | import io.holunda.polyflow.view.ProcessVariable 4 | import io.holunda.polyflow.view.query.process.variable.ProcessVariableFilter 5 | import io.holunda.polyflow.view.query.process.variable.ProcessVariableFilterType 6 | 7 | /** 8 | * Filter to query for a list of variables. Every variable present in the list matches the filter. 9 | */ 10 | data class ProcessVariableFilterOneOf( 11 | val processVariableNames: Set 12 | ) : ProcessVariableFilter { 13 | 14 | init { 15 | require(processVariableNames.isNotEmpty()) { "You must specify at least one variable for this filter." } 16 | } 17 | 18 | override val type: ProcessVariableFilterType = ProcessVariableFilterType.INCLUDE 19 | override fun apply(variable: ProcessVariable): Boolean = processVariableNames.contains(variable.variableName) 20 | } 21 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/AllTasksQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.Task 4 | 5 | /** 6 | * Query for all tasks. 7 | * @param page - page to read, zero-based index. 8 | * @param size - size of the page 9 | * @param sort - optional attribute to sort by. 10 | * @param filters - the filters to further filter down the tasks. 11 | */ 12 | data class AllTasksQuery( 13 | override val page: Int = 0, 14 | override val size: Int = Int.MAX_VALUE, 15 | override val sort: List = listOf(), 16 | override val filters: List = listOf() 17 | ) : PageableSortableFilteredTaskQuery { 18 | 19 | @Deprecated("Please use other constructor setting sort as List") 20 | constructor(page: Int = 0, size: Int = Int.MAX_VALUE, sort: String?, filters: List = listOf()): this( 21 | page = page, 22 | size = size, 23 | sort = if (sort.isNullOrBlank()) { 24 | listOf() 25 | } else { 26 | listOf(sort) 27 | }, 28 | filters = filters 29 | ) 30 | 31 | override fun applyFilter(element: Task): Boolean = true 32 | } 33 | 34 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/ApplicationWithTaskCount.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | /** 4 | * Information about amount of tasks per application. 5 | */ 6 | data class ApplicationWithTaskCount( 7 | val application: String, 8 | val taskCount: Int 9 | ) 10 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/PageableSortableFilteredTaskQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.Task 4 | import io.holunda.polyflow.view.query.FilterQuery 5 | import io.holunda.polyflow.view.query.PageableSortableQuery 6 | 7 | /** 8 | * Pageable and sortable task query containing filters. 9 | */ 10 | interface PageableSortableFilteredTaskQuery : FilterQuery, PageableSortableQuery { 11 | val filters: List 12 | } 13 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/TaskAttributeNamesQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.Task 4 | import io.holunda.polyflow.view.auth.User 5 | import io.holunda.polyflow.view.query.FilterQuery 6 | import io.holunda.polyflow.view.query.PageableSortableQuery 7 | 8 | /** 9 | * Query for tasks attribute names. 10 | * @param user - the user with groups accessing the tasks. If non is passed, all task attributes will be queried. 11 | * @param assignedToMeOnly flag indicating if the resulting tasks must be assigned to the user only. 12 | */ 13 | data class TaskAttributeNamesQuery( 14 | val user: User?, 15 | val assignedToMeOnly: Boolean = false, 16 | ) : FilterQuery { 17 | 18 | override fun applyFilter(element: Task): Boolean = true 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/TaskAttributeNamesQueryResult.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.query.PageableSortableQuery 4 | import io.holunda.polyflow.view.query.QueryResult 5 | 6 | /** 7 | * Result of query for multiple task attributes. 8 | */ 9 | data class TaskAttributeNamesQueryResult( 10 | override val elements: List, 11 | override val totalElementCount: Int = elements.size 12 | ) : QueryResult(elements = elements, totalElementCount = totalElementCount) { 13 | override fun slice(query: PageableSortableQuery) = this.copy(elements = super.slice(query).elements) 14 | } 15 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/TaskAttributeValuesQueryResult.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.Task 4 | import io.holunda.polyflow.view.query.PageableSortableQuery 5 | import io.holunda.polyflow.view.query.QueryResult 6 | 7 | /** 8 | * Result of query for multiple task attributes. 9 | */ 10 | data class TaskAttributeValuesQueryResult( 11 | override val elements: List, 12 | override val totalElementCount: Int = elements.size 13 | ) : QueryResult(elements = elements, totalElementCount = totalElementCount) { 14 | override fun slice(query: PageableSortableQuery) = this.copy(elements = super.slice(query).elements) 15 | } 16 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/TaskCountByApplicationQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | /** 4 | * Query for amount of tasks for every application. 5 | */ 6 | class TaskCountByApplicationQuery { 7 | 8 | /* 9 | * This is a marker class. All instances should be equal. 10 | */ 11 | override fun equals(other: Any?): Boolean { 12 | return (other is TaskCountByApplicationQuery) 13 | } 14 | 15 | /* 16 | * This is a marker class. All instances should be equal. 17 | */ 18 | override fun hashCode(): Int { 19 | return 1329081230; 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/TaskForIdQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.Task 4 | import io.holunda.polyflow.view.query.FilterQuery 5 | 6 | /** 7 | * Query for task with a given id. 8 | * @param id task id. 9 | */ 10 | data class TaskForIdQuery(val id: String) : FilterQuery { 11 | override fun applyFilter(element: Task): Boolean = element.id == id 12 | } 13 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/TaskQueryResult.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.Task 4 | import io.holunda.polyflow.view.query.PageableSortableQuery 5 | import io.holunda.polyflow.view.query.QueryResult 6 | 7 | /** 8 | * Result of query for multiple tasks. 9 | */ 10 | data class TaskQueryResult( 11 | override val elements: List, 12 | override val totalElementCount: Int = elements.size 13 | ) : QueryResult(elements = elements, totalElementCount = totalElementCount) { 14 | override fun slice(query: PageableSortableQuery) = this.copy(elements = super.slice(query).elements) 15 | } 16 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/TaskWithDataEntriesForIdQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.TaskWithDataEntries 4 | import io.holunda.polyflow.view.query.FilterQuery 5 | 6 | 7 | /** 8 | * Query for task with given id with correlated data entries. 9 | * @param id task id. 10 | */ 11 | data class TaskWithDataEntriesForIdQuery(val id: String) : FilterQuery { 12 | override fun applyFilter(element: TaskWithDataEntries): Boolean = TaskForIdQuery(id).applyFilter(element.task) 13 | } 14 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/TasksForApplicationQuery.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.Task 4 | import io.holunda.polyflow.view.query.FilterQuery 5 | 6 | /** 7 | * Query for task of a certain process application. 8 | * @param applicationName the name of the process application. 9 | */ 10 | data class TasksForApplicationQuery(val applicationName: String) : FilterQuery { 11 | override fun applyFilter(element: Task): Boolean = element.sourceReference.applicationName == applicationName 12 | } 13 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/query/task/TasksWithDataEntriesQueryResult.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.polyflow.view.TaskWithDataEntries 4 | import io.holunda.polyflow.view.query.PageableSortableQuery 5 | import io.holunda.polyflow.view.query.QueryResult 6 | 7 | /** 8 | * Result for query for multiple tasks with data entries. 9 | */ 10 | data class TasksWithDataEntriesQueryResult( 11 | override val elements: List, 12 | override val totalElementCount: Int = elements.size 13 | ) : QueryResult(elements = elements, totalElementCount = totalElementCount) { 14 | override fun slice(query: PageableSortableQuery) = this.copy(elements = super.slice(query).elements) 15 | } 16 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/sort/DataEntryComparator.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.sort 2 | 3 | import io.holunda.polyflow.view.DataEntry 4 | import io.holunda.polyflow.view.filter.extractValue 5 | import java.lang.reflect.Field 6 | import java.util.Comparator 7 | import javax.xml.datatype.DatatypeConstants 8 | 9 | 10 | /** 11 | * Comparator of data entries to be used in a sort. 12 | */ 13 | data class DataEntryComparator( 14 | private val fieldSort: Pair 15 | ) : Comparator { 16 | 17 | override fun compare(o1: DataEntry, o2: DataEntry): Int { 18 | return try { 19 | 20 | val v1 = extractValue(o1, this.fieldSort.first) 21 | val v2 = extractValue(o2, this.fieldSort.first) 22 | 23 | when (findCompareMode(v1, v2)) { 24 | CompareMode.DEFAULT -> compareActual(fieldSort, v1, v2) 25 | CompareMode.LESS_THAN -> -1 * this.fieldSort.second.modifier 26 | CompareMode.GREATER_THAN -> 1 * this.fieldSort.second.modifier 27 | CompareMode.EQUAL -> 0 * this.fieldSort.second.modifier 28 | } 29 | } catch (e: Exception) { 30 | DatatypeConstants.LESSER 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/sort/TaskComparator.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.sort 2 | 3 | import io.holunda.polyflow.view.Task 4 | import io.holunda.polyflow.view.TaskWithDataEntries 5 | import io.holunda.polyflow.view.filter.extractValue 6 | import java.lang.reflect.Field 7 | import javax.xml.datatype.DatatypeConstants.LESSER 8 | 9 | /** 10 | * Comparator for Tasks with Data Entries 11 | */ 12 | data class TaskComparator( 13 | private val fieldSort: Pair 14 | ) : Comparator { 15 | override fun compare(o1: Task, o2: Task): Int { 16 | return try { 17 | 18 | val v1 = extractValue(o1, this.fieldSort.first) 19 | val v2 = extractValue(o2, this.fieldSort.first) 20 | 21 | when (findCompareMode(v1, v2)) { 22 | CompareMode.DEFAULT -> compareActual(fieldSort, v1, v2) 23 | CompareMode.LESS_THAN -> -1 * this.fieldSort.second.modifier 24 | CompareMode.GREATER_THAN -> 1 * this.fieldSort.second.modifier 25 | CompareMode.EQUAL -> 0 * this.fieldSort.second.modifier 26 | } 27 | } catch (e: Exception) { 28 | LESSER 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /view/view-api/src/main/kotlin/sort/TasksWithDataEntriesComparator.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.sort 2 | 3 | import io.holunda.polyflow.view.TaskWithDataEntries 4 | import io.holunda.polyflow.view.filter.extractValue 5 | import java.lang.reflect.Field 6 | import javax.xml.datatype.DatatypeConstants.LESSER 7 | 8 | /** 9 | * Comparator for Tasks with Data Entries 10 | */ 11 | data class TasksWithDataEntriesComparator( 12 | private val fieldSort: Pair 13 | ) : Comparator { 14 | override fun compare(o1: TaskWithDataEntries, o2: TaskWithDataEntries): Int { 15 | return try { 16 | 17 | val v1 = extractValue(o1.task, this.fieldSort.first) 18 | val v2 = extractValue(o2.task, this.fieldSort.first) 19 | 20 | when (findCompareMode(v1, v2)) { 21 | CompareMode.DEFAULT -> compareActual(fieldSort, v1, v2) 22 | CompareMode.LESS_THAN -> -1 * this.fieldSort.second.modifier 23 | CompareMode.GREATER_THAN -> 1 * this.fieldSort.second.modifier 24 | CompareMode.EQUAL -> 0 * this.fieldSort.second.modifier 25 | } 26 | } catch (e: Exception) { 27 | LESSER 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /view/view-api/src/test/kotlin/DataEntryTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.junit.jupiter.api.Test 5 | 6 | class DataEntryTest { 7 | 8 | @Test 9 | fun `has identity`() { 10 | assertThat(DataEntry( 11 | entryType = "type", 12 | entryId = "foo", 13 | name = "some", 14 | applicationName = "app1", 15 | type = "myType" 16 | ).identity).isEqualTo("type#foo") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /view/view-api/src/test/kotlin/query/data/DataEntryForIdentityQueryTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.data 2 | 3 | import io.holunda.polyflow.view.DataEntry 4 | import org.assertj.core.api.Assertions.assertThat 5 | import org.junit.jupiter.api.Test 6 | 7 | internal class DataEntryForIdentityQueryTest { 8 | 9 | private val dataEntry = DataEntry( 10 | entryType = "io.type", 11 | entryId = "0239480234", 12 | type = "data entry", 13 | applicationName = "test-application", 14 | name = "Data Entry for case 4711", 15 | ) 16 | 17 | @Test 18 | fun `should filter by identity`() { 19 | assertThat(DataEntryForIdentityQuery(entryType = "io.type", entryId = "0239480234").applyFilter(dataEntry)).isTrue 20 | assertThat(DataEntryForIdentityQuery(entryType = "other.type", entryId = "0239480234").applyFilter(dataEntry)).isFalse 21 | assertThat(DataEntryForIdentityQuery(entryType = "io.type", entryId = "other-id").applyFilter(dataEntry)).isFalse 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /view/view-api/src/test/kotlin/query/process/ProcessInstanceByStateQueryTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.process 2 | 3 | import io.holunda.camunda.taskpool.api.task.ProcessReference 4 | import io.holunda.polyflow.view.ProcessInstance 5 | import io.holunda.polyflow.view.ProcessInstanceState 6 | import org.assertj.core.api.Assertions.assertThat 7 | import org.junit.jupiter.api.Test 8 | 9 | internal class ProcessInstanceByStateQueryTest { 10 | 11 | private val processInstance = ProcessInstance( 12 | processInstanceId = "9034278213", 13 | sourceReference = ProcessReference( 14 | instanceId = "instance-id", 15 | executionId = "exec-id", 16 | definitionId = "def-id", 17 | definitionKey = "def-key", 18 | name = "process name", 19 | applicationName = "test-application" 20 | ), 21 | state = ProcessInstanceState.RUNNING 22 | ) 23 | 24 | @Test 25 | fun `should filter by state`() { 26 | assertThat(ProcessInstancesByStateQuery(states = setOf(ProcessInstanceState.RUNNING)).applyFilter(processInstance)).isTrue 27 | assertThat(ProcessInstancesByStateQuery(states = setOf(ProcessInstanceState.FINISHED)).applyFilter(processInstance)).isFalse 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /view/view-api/src/test/kotlin/query/task/AllTasksQueryTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.camunda.taskpool.api.task.ProcessReference 4 | import io.holunda.polyflow.view.Task 5 | import io.holunda.polyflow.view.auth.User 6 | import org.assertj.core.api.Assertions.assertThat 7 | import org.junit.jupiter.api.Test 8 | 9 | class AllTasksQueryTest { 10 | private val task = Task( 11 | id = "923847239", 12 | sourceReference = ProcessReference( 13 | instanceId = "instance-id", 14 | executionId = "exec-id", 15 | definitionId = "def-id", 16 | definitionKey = "def-key", 17 | name = "process name", 18 | applicationName = "test-application" 19 | ), 20 | name = "task 1", 21 | description = "description", 22 | taskDefinitionKey = "task-def", 23 | candidateUsers = setOf("kermit"), 24 | assignee = "piggy", 25 | candidateGroups = setOf("muppets"), 26 | ) 27 | 28 | @Test 29 | fun `should always return true`() { 30 | assertThat(AllTasksQuery().applyFilter(task)).isTrue 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /view/view-api/src/test/kotlin/query/task/TaskForIdQueryTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.camunda.taskpool.api.task.ProcessReference 4 | import io.holunda.polyflow.view.Task 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.junit.jupiter.api.Test 7 | 8 | class TaskForIdQueryTest { 9 | private val task = Task( 10 | id = "923847239", 11 | sourceReference = ProcessReference( 12 | instanceId = "instance-id", 13 | executionId = "exec-id", 14 | definitionId = "def-id", 15 | definitionKey = "def-key", 16 | name = "process name", 17 | applicationName = "test-application" 18 | ), 19 | taskDefinitionKey = "task-def" 20 | ) 21 | 22 | @Test 23 | fun `should filter by id`() { 24 | assertThat(TaskForIdQuery(id = "923847239").applyFilter(task)).isTrue 25 | assertThat(TaskForIdQuery(id = "other-id").applyFilter(task)).isFalse 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /view/view-api/src/test/kotlin/query/task/TasksForApplicationQueryTest.kt: -------------------------------------------------------------------------------- 1 | package io.holunda.polyflow.view.query.task 2 | 3 | import io.holunda.camunda.taskpool.api.task.ProcessReference 4 | import io.holunda.polyflow.view.Task 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.junit.jupiter.api.Test 7 | 8 | class TasksForApplicationQueryTest { 9 | private val task = Task( 10 | id = "923847239", 11 | sourceReference = ProcessReference( 12 | instanceId = "instance-id", 13 | executionId = "exec-id", 14 | definitionId = "def-id", 15 | definitionKey = "def-key", 16 | name = "process name", 17 | applicationName = "test-application" 18 | ), 19 | taskDefinitionKey = "task-def" 20 | ) 21 | 22 | @Test 23 | fun `should filter by application`() { 24 | assertThat(TasksForApplicationQuery(applicationName = "test-application").applyFilter(task)).isTrue 25 | assertThat(TasksForApplicationQuery(applicationName = "other-application").applyFilter(task)).isFalse 26 | } 27 | } 28 | --------------------------------------------------------------------------------