diff --git a/README.md b/README.md index 4cc8f4fb1d..0ac3377164 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,12 @@ A Serverless Workflow service that works as a Github bot application, which reac * [on Quarkus](serverless-workflow-examples/serverless-workflow-github-showcase) +## Serverless Workflow Correlation + +* [on Quarkus (JDBC)](serverless-workflow-examples/serverless-workflow-correlation-quarkus) +* [on Quarkus (MongoDB)](serverless-workflow-examples/serverless-workflow-correlation-mongodb-quarkus) + + ## Other Misc Examples - Onboarding example combining 1 process and two decision services: see [README.md](kogito-quarkus-examples/onboarding-example/README.md) diff --git a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/main/java/org/kie/kogito/examples/BaseWorkItemHandlerConfig.java b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/main/java/org/kie/kogito/examples/BaseWorkItemHandlerConfig.java index ab82bcc7cc..9b9d6ad92e 100644 --- a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/main/java/org/kie/kogito/examples/BaseWorkItemHandlerConfig.java +++ b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/main/java/org/kie/kogito/examples/BaseWorkItemHandlerConfig.java @@ -31,7 +31,7 @@ import org.kie.kogito.addons.k8s.LocalEndpointDiscovery; import org.kie.kogito.addons.quarkus.k8s.workitems.QuarkusDiscoveredEndpointCaller; import org.kie.kogito.examples.onboarding.DecisionTaskWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.impl.DefaultWorkItemHandlerConfig; import jakarta.annotation.PostConstruct; diff --git a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/main/java/org/kie/kogito/examples/onboarding/DecisionTaskWorkItemHandler.java b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/main/java/org/kie/kogito/examples/onboarding/DecisionTaskWorkItemHandler.java index 25ffb1aa04..8ddf1cd26f 100644 --- a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/main/java/org/kie/kogito/examples/onboarding/DecisionTaskWorkItemHandler.java +++ b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/main/java/org/kie/kogito/examples/onboarding/DecisionTaskWorkItemHandler.java @@ -19,15 +19,18 @@ package org.kie.kogito.examples.onboarding; import java.util.Map; +import java.util.Optional; import org.kie.kogito.addons.quarkus.k8s.workitems.QuarkusDiscoveredEndpointCaller; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.WorkItemTransition; +import org.kie.kogito.process.workitems.impl.DefaultKogitoWorkItemHandler; import jakarta.ws.rs.HttpMethod; -public class DecisionTaskWorkItemHandler implements KogitoWorkItemHandler { +public class DecisionTaskWorkItemHandler extends DefaultKogitoWorkItemHandler { private QuarkusDiscoveredEndpointCaller endpointCaller; @@ -36,14 +39,9 @@ public DecisionTaskWorkItemHandler(QuarkusDiscoveredEndpointCaller endpointCalle } @Override - public void executeWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { + public Optional activateWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { Map results = endpointCaller.discoverAndCall(workItem, System.getenv("NAMESPACE"), "Decision", HttpMethod.POST); - manager.completeWorkItem(workItem.getStringId(), results); - } - - @Override - public void abortWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { - + return Optional.of(handler.completeTransition(workItem.getPhaseStatus(), results)); } @Override diff --git a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/WorkItemHandlerConfig.java b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/WorkItemHandlerConfig.java index 98dc9a2482..77926dd050 100644 --- a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/WorkItemHandlerConfig.java +++ b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/WorkItemHandlerConfig.java @@ -19,7 +19,7 @@ package org.kie.kogito.examples; import org.kie.kogito.examples.test.RecordedOutputWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; public class WorkItemHandlerConfig extends BaseWorkItemHandlerConfig { diff --git a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/onboarding/OnboardingEndpointIT.java b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/onboarding/OnboardingEndpointIT.java index d640de590d..70d1de4b0e 100644 --- a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/onboarding/OnboardingEndpointIT.java +++ b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/onboarding/OnboardingEndpointIT.java @@ -28,8 +28,8 @@ import org.junit.jupiter.api.Test; import org.kie.kogito.examples.test.RecordedOutputWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.ProcessConfig; import org.kie.kogito.testcontainers.quarkus.InfinispanQuarkusTestResource; diff --git a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/test/RecordedOutputWorkItemHandler.java b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/test/RecordedOutputWorkItemHandler.java index 05a6799916..f7559da0d9 100644 --- a/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/test/RecordedOutputWorkItemHandler.java +++ b/kogito-quarkus-examples/onboarding-example/onboarding-quarkus/src/test/java/org/kie/kogito/examples/test/RecordedOutputWorkItemHandler.java @@ -20,26 +20,23 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.function.Function; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.WorkItemTransition; +import org.kie.kogito.process.workitems.impl.DefaultKogitoWorkItemHandler; -public class RecordedOutputWorkItemHandler implements KogitoWorkItemHandler { +public class RecordedOutputWorkItemHandler extends DefaultKogitoWorkItemHandler { private Map>> recorded = new HashMap<>(); @Override - public void executeWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { + public Optional activateWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { Map results = recorded.remove(workItem.getParameter("TaskName")).apply(workItem); - - manager.completeWorkItem(workItem.getStringId(), results); - } - - @Override - public void abortWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { - + return Optional.of(handler.completeTransition(workItem.getPhaseStatus(), results)); } public void record(String name, Function> item) { diff --git a/kogito-quarkus-examples/pom.xml b/kogito-quarkus-examples/pom.xml index e2c3fbaa05..1b555b56d0 100644 --- a/kogito-quarkus-examples/pom.xml +++ b/kogito-quarkus-examples/pom.xml @@ -74,6 +74,7 @@ process-error-handling process-incubation-api-quarkus process-infinispan-persistence-quarkus + process-instance-migration-quarkus process-kafka-avro-multi-quarkus process-kafka-multi-quarkus process-kafka-persistence-quarkus @@ -140,6 +141,7 @@ pmml-quarkus-example process-business-rules-quarkus process-infinispan-persistence-quarkus + process-instance-migration-quarkus process-kafka-persistence-quarkus process-kafka-quickstart-quarkus process-knative-quickstart-quarkus diff --git a/kogito-quarkus-examples/process-error-handling/src/main/java/org/acme/wih/CustomTaskWorkItemHandler.java b/kogito-quarkus-examples/process-error-handling/src/main/java/org/acme/wih/CustomTaskWorkItemHandler.java index ee6309cd6b..aba8a9730e 100644 --- a/kogito-quarkus-examples/process-error-handling/src/main/java/org/acme/wih/CustomTaskWorkItemHandler.java +++ b/kogito-quarkus-examples/process-error-handling/src/main/java/org/acme/wih/CustomTaskWorkItemHandler.java @@ -20,20 +20,23 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.kie.api.runtime.process.ProcessWorkItemHandlerException; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.WorkItemTransition; +import org.kie.kogito.process.workitems.impl.DefaultKogitoWorkItemHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class CustomTaskWorkItemHandler implements KogitoWorkItemHandler { +public class CustomTaskWorkItemHandler extends DefaultKogitoWorkItemHandler { private static final Logger LOG = LoggerFactory.getLogger(CustomTaskWorkItemHandler.class); @Override - public void executeWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { + public Optional activateWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { LOG.debug("start"); LOG.debug("Passed parameters:"); @@ -51,15 +54,22 @@ public void executeWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manag if (input.matches("(RETRY|COMPLETE|RETHROW)")) { handleError(input); } else if (input.contentEquals("ABORT")) { - manager.abortWorkItem(workItem.getStringId()); + return Optional.of(handler.abortTransition(workItem.getPhaseStatus())); } else { // Don’t forget to finish the work item otherwise the process // will be active infinitely and never will pass the flow // to the next node. - manager.completeWorkItem(workItem.getStringId(), results); + return Optional.of(handler.completeTransition(workItem.getPhaseStatus(), results)); } LOG.debug("end"); + return Optional.empty(); + } + + @Override + public Optional abortWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workitem, WorkItemTransition transition) { + LOG.debug("ABORT!"); + return Optional.empty(); } private void handleError(String strategy) { @@ -68,9 +78,4 @@ private void handleError(String strategy) { new IllegalStateException(strategy + " strategy test")); } - @Override - public void abortWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { - LOG.debug("ABORT!"); - manager.abortWorkItem(workItem.getStringId()); - } } \ No newline at end of file diff --git a/kogito-quarkus-examples/process-instance-migration-quarkus/docker-compose/startServices.sh b/kogito-quarkus-examples/process-instance-migration-quarkus/docker-compose/startServices.sh index 8b0c6f4348..ecfa6633d3 100755 --- a/kogito-quarkus-examples/process-instance-migration-quarkus/docker-compose/startServices.sh +++ b/kogito-quarkus-examples/process-instance-migration-quarkus/docker-compose/startServices.sh @@ -31,9 +31,9 @@ echo "Kogito Image version: ${KOGITO_VERSION}" echo "KOGITO_VERSION=${KOGITO_VERSION}" > ".env" echo "COMPOSE_PROFILES='${PROFILE}'" >> ".env" -if [ "$(uname)" == "Darwin" ]; then +if [ "$(uname)" = "Darwin" ]; then echo "DOCKER_GATEWAY_HOST=kubernetes.docker.internal" >> ".env" -elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then +elif [ "$(expr substr $(uname -s) 1 5)" = "Linux" ]; then echo "DOCKER_GATEWAY_HOST=172.17.0.1" >> ".env" fi diff --git a/kogito-quarkus-examples/process-instance-migration-quarkus/pom.xml b/kogito-quarkus-examples/process-instance-migration-quarkus/pom.xml index e2a2181950..323a6a6333 100644 --- a/kogito-quarkus-examples/process-instance-migration-quarkus/pom.xml +++ b/kogito-quarkus-examples/process-instance-migration-quarkus/pom.xml @@ -130,12 +130,6 @@ kogito-addons-quarkus-data-index-postgresql - - - org.kie - kogito-addons-quarkus-data-index-persistence-postgresql - - org.kie diff --git a/kogito-quarkus-examples/process-instance-migration-quarkus/src/main/resources/application.properties b/kogito-quarkus-examples/process-instance-migration-quarkus/src/main/resources/application.properties index 077d6091e0..b9a0d64ef3 100644 --- a/kogito-quarkus-examples/process-instance-migration-quarkus/src/main/resources/application.properties +++ b/kogito-quarkus-examples/process-instance-migration-quarkus/src/main/resources/application.properties @@ -19,11 +19,7 @@ kogito.dataindex.http.url=http://localhost:8080 kogito.dataindex.ws.url=ws://localhost:8080 # run create tables scripts -quarkus.flyway.migrate-at-start=true -quarkus.flyway.baseline-on-migrate=true -quarkus.flyway.baseline-version=0.0 -quarkus.flyway.locations=classpath:/db/migration,classpath:/db/jobs-service,classpath:/db/data-audit/postgresql -quarkus.flyway.table=FLYWAY_RUNTIME_SERVICE +kie.flyway.enabled=true kogito.persistence.type=jdbc quarkus.datasource.db-kind=postgresql diff --git a/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/docker-compose.yml b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/docker-compose.yml index 4aa58ffa91..0a5bcb72e0 100644 --- a/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/docker-compose.yml +++ b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/docker-compose.yml @@ -21,29 +21,47 @@ version: "3" services: postgres-compose: - image: postgres:13.4-alpine3.14 + image: postgres:16.1-alpine3.19 + container_name: postgres environment: - POSTGRES_PASSWORD: pass + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres ports: - 5432:5432 volumes: - ./sql:/docker-entrypoint-initdb.d/ + healthcheck: + test: [ "CMD", "pg_isready", "-q", "-d", "kogito", "-U", "kogito-user" ] + timeout: 45s + interval: 10s + retries: 50 networks: - postgres-compose-network - container_name: postgres-container pgadmin-compose: - image: dpage/pgadmin4:5.0 - environment: - PGADMIN_DEFAULT_EMAIL: user@user.org - PGADMIN_DEFAULT_PASSWORD: pass + image: dpage/pgadmin4:8.2 + container_name: pgadmin ports: - 8055:80 depends_on: - postgres-compose + volumes: + - ./pgadmin/servers.json:/pgadmin4/servers.json + - ./pgadmin/pgpass:/pgadmin4/pgpass + entrypoint: > + /bin/sh -c " + cp -f /pgadmin4/pgpass /var/lib/pgadmin/; + chmod 600 /var/lib/pgadmin/pgpass; + /entrypoint.sh + " + environment: + PGADMIN_DEFAULT_EMAIL: user@kogito.org + PGADMIN_DEFAULT_PASSWORD: pass + PGADMIN_CONFIG_SERVER_MODE: "False" + PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: "False" + GUNICORN_ACCESS_LOGFILE: "/dev/null" networks: - postgres-compose-network - container_name: pgadmin-container networks: postgres-compose-network: diff --git a/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/pgadmin/pgpass b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/pgadmin/pgpass new file mode 100644 index 0000000000..2e0fbd6a33 --- /dev/null +++ b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/pgadmin/pgpass @@ -0,0 +1,2 @@ +postgres:5432:kogito:kogito-user:kogito-pass +postgres:5432:postgres:kogito-user:kogito-pass \ No newline at end of file diff --git a/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/pgadmin/servers.json b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/pgadmin/servers.json new file mode 100644 index 0000000000..caafe268c0 --- /dev/null +++ b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/pgadmin/servers.json @@ -0,0 +1,14 @@ +{ + "Servers": { + "1": { + "Name": "kogito", + "Group": "Servers", + "Host": "postgres", + "Port": 5432, + "MaintenanceDB": "kogito", + "Username": "kogito-user", + "SSLMode": "disable", + "PassFile": "/var/lib/pgadmin/pgpass" + } + } +} diff --git a/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/sql/init.sql b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/sql/init.sql index 8cfbe001cd..8246ed59ce 100644 --- a/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/sql/init.sql +++ b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/docker-compose/sql/init.sql @@ -24,7 +24,7 @@ CREATE ROLE "kogito-user" WITH CREATEDB CREATEROLE NOREPLICATION - ENCRYPTED PASSWORD 'md54adb613a8ffdd707e032c918d791e2e5'; + PASSWORD 'kogito-pass'; CREATE DATABASE kogito WITH diff --git a/kogito-quarkus-examples/process-postgresql-persistence-quarkus/src/main/resources/application.properties b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/src/main/resources/application.properties index 8919fc3679..9a96b0fb1e 100644 --- a/kogito-quarkus-examples/process-postgresql-persistence-quarkus/src/main/resources/application.properties +++ b/kogito-quarkus-examples/process-postgresql-persistence-quarkus/src/main/resources/application.properties @@ -24,4 +24,7 @@ quarkus.datasource.db-kind=postgresql %prod.quarkus.datasource.username=kogito-user %prod.quarkus.datasource.password=kogito-pass %prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/kogito -quarkus.flyway.migrate-at-start=true + +kie.flyway.enabled=true + +%dev.quarkus.kogito.devservices.enabled=false diff --git a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/config/CustomWorkItemHandlerConfig.java b/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/config/CustomWorkItemHandlerConfig.java index 2e973282b8..745f9f2e06 100644 --- a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/config/CustomWorkItemHandlerConfig.java +++ b/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/config/CustomWorkItemHandlerConfig.java @@ -18,8 +18,7 @@ */ package org.acme.travels.config; -import org.acme.travels.usertasks.CustomHumanTaskLifeCycle; -import org.jbpm.process.instance.impl.humantask.HumanTaskWorkItemHandler; +import org.acme.travels.usertasks.CustomHumanTaskWorkItemHandler; import org.kie.kogito.process.impl.DefaultWorkItemHandlerConfig; import jakarta.enterprise.context.ApplicationScoped; @@ -37,6 +36,6 @@ @ApplicationScoped public class CustomWorkItemHandlerConfig extends DefaultWorkItemHandlerConfig { { - register("Human Task", new HumanTaskWorkItemHandler(new CustomHumanTaskLifeCycle())); + register("Human Task", new CustomHumanTaskWorkItemHandler()); } } diff --git a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CustomHumanTaskLifeCycle.java b/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CustomHumanTaskLifeCycle.java deleted file mode 100644 index c83b80302c..0000000000 --- a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CustomHumanTaskLifeCycle.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.acme.travels.usertasks; - -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.jbpm.process.instance.impl.humantask.BaseHumanTaskLifeCycle; -import org.jbpm.process.instance.impl.humantask.InternalHumanTaskWorkItem; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.humantask.phases.Release; -import org.jbpm.process.instance.impl.humantask.phases.Skip; -import org.jbpm.process.instance.impl.workitem.Abort; -import org.jbpm.process.instance.impl.workitem.Active; -import org.jbpm.process.instance.impl.workitem.Complete; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemManager; -import org.kie.kogito.process.workitem.InvalidLifeCyclePhaseException; -import org.kie.kogito.process.workitem.InvalidTransitionException; -import org.kie.kogito.process.workitem.LifeCycle; -import org.kie.kogito.process.workitem.LifeCyclePhase; -import org.kie.kogito.process.workitem.NotAuthorizedException; -import org.kie.kogito.process.workitem.Policy; -import org.kie.kogito.process.workitem.Transition; -import org.kie.kogito.process.workitems.InternalKogitoWorkItemManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Custom life cycle definition for human tasks. It comes with following phases - * - *
    - *
  • Active
  • - *
  • Claim
  • - *
  • Release
  • - *
  • Start
  • - *
  • Complete - extended one that allows to only complete started tasks
  • - *
  • Skip
  • - *
  • Abort
  • - *
- * At the beginning human task enters - * - *
- * Active
- * 
- * - * phase. From there it can go to - * - *
    - *
  • Claim
  • - *
  • Skip
  • - *
  • Abort
  • - *
- * - * at any time. At each phase data can be associated and by that set on work item. - * - * Completion can only be performed on started tasks. - */ -public class CustomHumanTaskLifeCycle implements LifeCycle> { - - private static final Logger logger = LoggerFactory.getLogger(BaseHumanTaskLifeCycle.class); - - private Map phases = new LinkedHashMap<>(); - - public CustomHumanTaskLifeCycle() { - phases.put(Claim.ID, new Claim()); - phases.put(Release.ID, new Release()); - phases.put(Start.ID, new Start()); - phases.put(Complete.ID, new CompleteStartedOnly()); - phases.put(Skip.ID, new Skip()); - phases.put(Active.ID, new Active()); - phases.put(Abort.ID, new Abort()); - } - - @Override - public LifeCyclePhase phaseById(String phaseId) { - return phases.get(phaseId); - } - - @Override - public Collection phases() { - return phases.values(); - } - - @Override - public Map transitionTo(KogitoWorkItem workItem, KogitoWorkItemManager manager, Transition> transition) { - logger.debug("Transition method invoked for work item {} to transition to {}, currently in phase {} and status {}", workItem.getStringId(), transition.phase(), workItem.getPhaseId(), - workItem.getPhaseStatus()); - - InternalHumanTaskWorkItem humanTaskWorkItem = (InternalHumanTaskWorkItem) workItem; - - LifeCyclePhase targetPhase = phases.get(transition.phase()); - if (targetPhase == null) { - logger.debug("Target life cycle phase '{}' does not exist in {}", transition.phase(), this.getClass().getSimpleName()); - throw new InvalidLifeCyclePhaseException(transition.phase()); - } - - LifeCyclePhase currentPhase = phases.get(humanTaskWorkItem.getPhaseId()); - - if (!targetPhase.canTransition(currentPhase)) { - logger.debug("Target life cycle phase '{}' cannot transition from current state '{}'", targetPhase.id(), currentPhase.id()); - throw new InvalidTransitionException("Cannot transition from " + humanTaskWorkItem.getPhaseId() + " to " + targetPhase.id()); - } - - if (!targetPhase.id().equals(Active.ID) && !targetPhase.id().equals(Abort.ID) && !humanTaskWorkItem.enforce(transition.policies().toArray(new Policy[transition.policies().size()]))) { - throw new NotAuthorizedException("User is not authorized to access task instance with id " + humanTaskWorkItem.getStringId()); - } - - humanTaskWorkItem.setPhaseId(targetPhase.id()); - humanTaskWorkItem.setPhaseStatus(targetPhase.status()); - - targetPhase.apply(humanTaskWorkItem, transition); - if (transition.data() != null) { - logger.debug("Updating data for phase {} and work item {}", targetPhase.id(), humanTaskWorkItem.getStringId()); - humanTaskWorkItem.getResults().putAll(transition.data()); - } - logger.debug("Transition for work item {} to {} done, currently in phase {} and status {}", workItem.getStringId(), transition.phase(), workItem.getPhaseId(), workItem.getPhaseStatus()); - - if (targetPhase.isTerminating()) { - logger.debug("Target life cycle phase '{}' is terminiating, completing work item {}", targetPhase.id(), humanTaskWorkItem.getStringId()); - // since target life cycle phase is terminating completing work item - ((InternalKogitoWorkItemManager) manager).internalCompleteWorkItem(humanTaskWorkItem); - } - - return data(humanTaskWorkItem); - } - - @Override - public Map data(KogitoWorkItem workItem) { - return ((InternalHumanTaskWorkItem) workItem).getResults(); - } -} diff --git a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CustomHumanTaskWorkItemHandler.java b/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CustomHumanTaskWorkItemHandler.java new file mode 100644 index 0000000000..0a3fa0eabb --- /dev/null +++ b/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CustomHumanTaskWorkItemHandler.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.acme.travels.usertasks; + +import java.util.Optional; + +import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.WorkItemLifeCycle; +import org.kie.kogito.internal.process.workitem.WorkItemPhaseState; +import org.kie.kogito.internal.process.workitem.WorkItemTerminationType; +import org.kie.kogito.internal.process.workitem.WorkItemTransition; +import org.kie.kogito.process.workitems.impl.DefaultKogitoWorkItemHandler; +import org.kie.kogito.process.workitems.impl.DefaultWorkItemLifeCycle; +import org.kie.kogito.process.workitems.impl.DefaultWorkItemLifeCyclePhase; + +public class CustomHumanTaskWorkItemHandler extends DefaultKogitoWorkItemHandler { + + public static final String TRANSITION_COMPLETE = "complete"; + public static final String TRANSITION_ABORT = "abort"; + public static final String TRANSITION_ACTIVATE = "activate"; + public static final String TRANSITION_START = "start"; + public static final String TRANSITION_SKIP = "skip"; + + @Override + public WorkItemLifeCycle initialize() { + WorkItemPhaseState initialized = WorkItemPhaseState.initialized(); + WorkItemPhaseState completed = WorkItemPhaseState.of("Completed", WorkItemTerminationType.COMPLETE); + WorkItemPhaseState aborted = WorkItemPhaseState.of("Aborted", WorkItemTerminationType.ABORT); + WorkItemPhaseState activated = WorkItemPhaseState.of("Activated"); + WorkItemPhaseState started = WorkItemPhaseState.of("Started"); + + DefaultWorkItemLifeCyclePhase active = new DefaultWorkItemLifeCyclePhase(TRANSITION_ACTIVATE, initialized, activated, this::activateWorkItemHandler); + DefaultWorkItemLifeCyclePhase start = new DefaultWorkItemLifeCyclePhase(TRANSITION_START, activated, started, this::activateWorkItemHandler); + DefaultWorkItemLifeCyclePhase complete = new DefaultWorkItemLifeCyclePhase(TRANSITION_COMPLETE, started, completed, this::completeWorkItemHandler); + DefaultWorkItemLifeCyclePhase abort = new DefaultWorkItemLifeCyclePhase(TRANSITION_ABORT, started, aborted, this::abortWorkItemHandler); + + return new DefaultWorkItemLifeCycle(active, start, abort, complete); + } + + @Override + public Optional completeWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workitem, WorkItemTransition transition) { + getUserFromTransition(transition).ifPresent(e -> workitem.setOutput("ActorId", e)); + return Optional.empty(); + } + + private Optional getUserFromTransition(WorkItemTransition transition) { + Optional securityPolicy = transition.policies().stream().filter(SecurityPolicy.class::isInstance).map(SecurityPolicy.class::cast).findAny(); + if (securityPolicy.isPresent()) { + return Optional.ofNullable(securityPolicy.get().getUser()); + } + return Optional.empty(); + } +} diff --git a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/Start.java b/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/Start.java deleted file mode 100644 index 7a5199de1c..0000000000 --- a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/Start.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.acme.travels.usertasks; - -import java.util.Arrays; -import java.util.List; - -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.humantask.phases.Release; -import org.jbpm.process.instance.impl.workitem.Active; -import org.kie.kogito.process.workitem.LifeCyclePhase; - -/** - * Start life cycle phase that applies to any human task. - * It will set the status to "Started" - * - * It can transition from - *
    - *
  • Active
  • - *
  • Claim
  • - *
  • Release
  • - *
- * - */ -public class Start implements LifeCyclePhase { - - public static final String ID = "start"; - public static final String STATUS = "Started"; - - private List allowedTransitions = Arrays.asList(Active.ID, Claim.ID, Release.ID); - - @Override - public String id() { - return ID; - } - - @Override - public String status() { - return STATUS; - } - - @Override - public boolean isTerminating() { - return false; - } - - @Override - public boolean canTransition(LifeCyclePhase phase) { - return allowedTransitions.contains(phase.id()); - } -} diff --git a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/test/java/org/acme/travels/custom/lifecycle/quarkus/ApprovalsProcessTest.java b/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/test/java/org/acme/travels/custom/lifecycle/quarkus/ApprovalsProcessTest.java index 573ab8f193..59af5b65fb 100644 --- a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/test/java/org/acme/travels/custom/lifecycle/quarkus/ApprovalsProcessTest.java +++ b/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/test/java/org/acme/travels/custom/lifecycle/quarkus/ApprovalsProcessTest.java @@ -25,25 +25,23 @@ import org.acme.travels.Address; import org.acme.travels.Traveller; -import org.acme.travels.usertasks.Start; -import org.jbpm.process.instance.impl.humantask.HumanTaskTransition; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.workitem.Complete; import org.junit.jupiter.api.Test; import org.kie.kogito.Model; import org.kie.kogito.auth.IdentityProvider; import org.kie.kogito.auth.IdentityProviders; import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.InvalidTransitionException; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessInstance; import org.kie.kogito.process.WorkItem; -import org.kie.kogito.process.workitem.InvalidTransitionException; import io.quarkus.test.junit.QuarkusTest; import jakarta.inject.Inject; import jakarta.inject.Named; +import static java.util.Collections.singletonList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -78,9 +76,12 @@ public void testApprovalProcess() { assertEquals(1, workItems.size()); Map results = new HashMap<>(); results.put("approved", true); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Start.ID, null, policy)); + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("start", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); + policy = SecurityPolicy.of(IdentityProviders.of("admin", singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -93,7 +94,8 @@ public void testApprovalProcess() { assertEquals(1, workItems.size()); results.put("approved", false); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Start.ID, null, policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("start", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); @@ -129,15 +131,17 @@ public void testApprovalProcessViaPhases() { final String wiId = workItems.get(0).getId(); // test to make sure you can't complete if the task is not in started state - assertThrows(InvalidTransitionException.class, () -> processInstance.transitionWorkItem(wiId, new HumanTaskTransition(Complete.ID, + assertThrows(InvalidTransitionException.class, () -> processInstance.completeWorkItem(wiId, Collections.singletonMap("approved", true), - SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("managers")))))); + SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("managers"))))); // now test going through phases - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Start.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", true), policy)); + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("start", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), Collections.singletonMap("approved", true), policy)); + policy = SecurityPolicy.of(IdentityProviders.of("admin", singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -149,9 +153,9 @@ public void testApprovalProcessViaPhases() { workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - // test that claim can be skipped - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Start.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", false), policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("start", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), Collections.singletonMap("approved", false), policy)); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); diff --git a/kogito-quarkus-examples/process-usertasks-quarkus/src/test/java/org/acme/travels/quarkus/ApprovalsProcessTest.java b/kogito-quarkus-examples/process-usertasks-quarkus/src/test/java/org/acme/travels/quarkus/ApprovalsProcessTest.java index a5a41285c3..b4a1690b2d 100644 --- a/kogito-quarkus-examples/process-usertasks-quarkus/src/test/java/org/acme/travels/quarkus/ApprovalsProcessTest.java +++ b/kogito-quarkus-examples/process-usertasks-quarkus/src/test/java/org/acme/travels/quarkus/ApprovalsProcessTest.java @@ -25,13 +25,11 @@ import org.acme.travels.Address; import org.acme.travels.Traveller; -import org.jbpm.process.instance.impl.humantask.HumanTaskTransition; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.workitem.Complete; import org.junit.jupiter.api.Test; import org.kie.kogito.Model; import org.kie.kogito.auth.IdentityProviders; import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessInstance; import org.kie.kogito.process.WorkItem; @@ -75,6 +73,7 @@ public void testApprovalProcess() { results.put("approved", true); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -117,9 +116,12 @@ public void testApprovalProcessViaPhases() { List workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", true), policy)); + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), Collections.singletonMap("approved", true), policy)); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -130,8 +132,9 @@ public void testApprovalProcessViaPhases() { workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", false), policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), Collections.singletonMap("approved", false), policy)); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); diff --git a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/docker-compose-postgresql.yml b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/docker-compose-postgresql.yml index cab2129fee..e7055af034 100755 --- a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/docker-compose-postgresql.yml +++ b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/docker-compose-postgresql.yml @@ -17,11 +17,11 @@ # under the License. # -version: '2.1' +version: '3' services: postgres: - image: postgres:13.4-alpine3.14 + image: postgres:16.1-alpine3.19 ports: - "5432:5432" volumes: @@ -32,19 +32,30 @@ services: interval: 10s retries: 50 environment: - - POSTGRES_USER=postgres - - POSTGRES_PASSWORD=postgres + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres - pgadmin-compose: - image: dpage/pgadmin4:5.0 - environment: - PGADMIN_DEFAULT_EMAIL: user@user.org - PGADMIN_DEFAULT_PASSWORD: pass + pgadmin: + image: dpage/pgadmin4:8.2 ports: - 8055:80 depends_on: - postgres - container_name: pgadmin-container + volumes: + - ./pgadmin/servers.json:/pgadmin4/servers.json + - ./pgadmin/pgpass:/pgadmin4/pgpass + entrypoint: > + /bin/sh -c " + cp -f /pgadmin4/pgpass /var/lib/pgadmin/; + chmod 600 /var/lib/pgadmin/pgpass; + /entrypoint.sh + " + environment: + PGADMIN_DEFAULT_EMAIL: user@kogito.org + PGADMIN_DEFAULT_PASSWORD: pass + PGADMIN_CONFIG_SERVER_MODE: "False" + PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: "False" + GUNICORN_ACCESS_LOGFILE: "/dev/null" zookeeper: container_name: zookeeper @@ -95,7 +106,7 @@ services: environment: DB_VENDOR: POSTGRES DB_ADDR: postgres - DB_DATABASE: kogito + DB_DATABASE: keycloak DB_USER: kogito-user DB_SCHEMA: public DB_PASSWORD: kogito-pass @@ -105,7 +116,7 @@ services: data-index: container_name: data-index - image: quay.io/kiegroup/kogito-data-index-postgresql:${KOGITO_VERSION} + image: docker.io/apache/incubator-kie-kogito-data-index-postgresql:${KOGITO_VERSION} ports: - "8180:8080" depends_on: @@ -119,13 +130,15 @@ services: QUARKUS_DATASOURCE_JDBC_URL: "jdbc:postgresql://postgres:5432/kogito" QUARKUS_DATASOURCE_USERNAME: kogito-user QUARKUS_DATASOURCE_PASSWORD: kogito-pass + QUARKUS_FLYWAY_MIGRATE_AT_START: "true" + QUARKUS_FLYWAY_BASELINE_ON_MIGRATE: "true" + QUARKUS_FLYWAY_TABLE: FLYWAY_DATA_INDEX KAFKA_BOOTSTRAP_SERVERS: kafka:29092 QUARKUS_HTTP_CORS_ORIGINS: "/.*/" - KOGITO_DATA_INDEX_PROPS: -Dquarkus.hibernate-orm.database.generation=update jobs-service: container_name: jobs-service - image: quay.io/kiegroup/kogito-jobs-service-postgresql:${KOGITO_VERSION} + image: docker.io/apache/incubator-kie-kogito-jobs-service-postgresql:${KOGITO_VERSION} ports: - "8580:8080" depends_on: @@ -138,7 +151,9 @@ services: QUARKUS_DATASOURCE_REACTIVE_URL: "postgresql://postgres:5432/kogito" QUARKUS_DATASOURCE_USERNAME: kogito-user QUARKUS_DATASOURCE_PASSWORD: kogito-pass + QUARKUS_FLYWAY_MIGRATE_AT_START: "true" QUARKUS_FLYWAY_BASELINE_ON_MIGRATE: "true" + QUARKUS_FLYWAY_TABLE: FLYWAY_JOBS_SERVICE KAFKA_BOOTSTRAP_SERVERS: kafka:29092 QUARKUS_PROFILE: events-support QUARKUS_HTTP_PORT: 8580 @@ -146,7 +161,7 @@ services: management-console: container_name: management-console - image: quay.io/kiegroup/kogito-management-console:${KOGITO_VERSION} + image: docker.io/apache/incubator-kie-kogito-management-console:${KOGITO_VERSION} ports: - "8280:8080" depends_on: @@ -159,15 +174,16 @@ services: volumes: - ../target/classes/META-INF/processSVG/:/home/kogito/data/svg/ environment: - KOGITO_DATAINDEX_HTTP_URL: http://${DOCKER_GATEWAY_HOST:-host.docker.internal}:8180/graphql - QUARKUS_HTTP_CORS_ORIGINS: "/.*/" - KOGITO_MANAGEMENT_CONSOLE_PROPS: -Dkogito.consoles.keycloak.config.url=http://localhost:8480/auth - -Dkogito.consoles.keycloak.config.health-check-url=http://localhost:8480/auth/realms/kogito/.well-known/openid-configuration - -Dkogito.svg.folder.path=/home/kogito/data/svg + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_KOGITO_ENV_MODE: "PROD" + RUNTIME_TOOLS_MANAGEMENT_CONSOLE_DATA_INDEX_ENDPOINT: http://${DOCKER_GATEWAY_HOST:-host.docker.internal}:8180/graphql + KOGITO_CONSOLES_KEYCLOAK_HEALTH_CHECK_URL: http://localhost:8480/auth/realms/kogito/.well-known/openid-configuration + KOGITO_CONSOLES_KEYCLOAK_URL: http://localhost:8480/auth + KOGITO_CONSOLES_KEYCLOAK_REALM: kogito + KOGITO_CONSOLES_KEYCLOAK_CLIENT_ID: kogito-console-quarkus task-console: container_name: task-console - image: quay.io/kiegroup/kogito-task-console:${KOGITO_VERSION} + image: docker.io/apache/incubator-kie-kogito-task-console:${KOGITO_VERSION} ports: - "8380:8080" depends_on: @@ -176,7 +192,9 @@ services: keycloak: condition: service_healthy environment: - KOGITO_DATAINDEX_HTTP_URL: http://${DOCKER_GATEWAY_HOST:-host.docker.internal}:8180/graphql - QUARKUS_HTTP_CORS_ORIGINS: "/.*/" - KOGITO_TASK_CONSOLE_PROPS: -Dkogito.consoles.keycloak.config.url=http://localhost:8480/auth - -Dkogito.consoles.keycloak.config.health-check-url=http://localhost:8480/auth/realms/kogito/.well-known/openid-configuration + RUNTIME_TOOLS_TASK_CONSOLE_KOGITO_ENV_MODE: "PROD" + RUNTIME_TOOLS_TASK_CONSOLE_DATA_INDEX_ENDPOINT: http://${DOCKER_GATEWAY_HOST:-host.docker.internal}:8180/graphql + KOGITO_CONSOLES_KEYCLOAK_HEALTH_CHECK_URL: http://localhost:8480/auth/realms/kogito/.well-known/openid-configuration + KOGITO_CONSOLES_KEYCLOAK_URL: http://localhost:8480/auth + KOGITO_CONSOLES_KEYCLOAK_REALM: kogito + KOGITO_CONSOLES_KEYCLOAK_CLIENT_ID: kogito-console-quarkus diff --git a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/pgadmin/pgpass b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/pgadmin/pgpass new file mode 100644 index 0000000000..2e0fbd6a33 --- /dev/null +++ b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/pgadmin/pgpass @@ -0,0 +1,2 @@ +postgres:5432:kogito:kogito-user:kogito-pass +postgres:5432:postgres:kogito-user:kogito-pass \ No newline at end of file diff --git a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/pgadmin/servers.json b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/pgadmin/servers.json new file mode 100644 index 0000000000..caafe268c0 --- /dev/null +++ b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/pgadmin/servers.json @@ -0,0 +1,14 @@ +{ + "Servers": { + "1": { + "Name": "kogito", + "Group": "Servers", + "Host": "postgres", + "Port": 5432, + "MaintenanceDB": "kogito", + "Username": "kogito-user", + "SSLMode": "disable", + "PassFile": "/var/lib/pgadmin/pgpass" + } + } +} diff --git a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/sql/init.sql b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/sql/init.sql index ee1a94650d..92ea9b4e5c 100644 --- a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/sql/init.sql +++ b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/sql/init.sql @@ -16,5 +16,18 @@ CREATE DATABASE kogito TABLESPACE = pg_default CONNECTION LIMIT = -1; +CREATE DATABASE keycloak + WITH + OWNER = "kogito-user" + ENCODING = 'UTF8' + LC_COLLATE = 'en_US.utf8' + LC_CTYPE = 'en_US.utf8' + TABLESPACE = pg_default + CONNECTION LIMIT = -1; + +GRANT ALL PRIVILEGES ON DATABASE postgres TO "kogito-user"; GRANT ALL PRIVILEGES ON DATABASE kogito TO "kogito-user"; GRANT ALL PRIVILEGES ON DATABASE kogito TO postgres; + +GRANT ALL PRIVILEGES ON DATABASE keycloak TO "kogito-user"; +GRANT ALL PRIVILEGES ON DATABASE keycloak TO postgres; \ No newline at end of file diff --git a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/startServices.sh b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/startServices.sh index 70fccff021..ad8e9bfb6b 100755 --- a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/startServices.sh +++ b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/docker-compose/startServices.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -27,7 +27,7 @@ echo "Project version: ${PROJECT_VERSION}" if [[ $PROJECT_VERSION == *SNAPSHOT ]]; then - KOGITO_VERSION="latest" + KOGITO_VERSION="main" else KOGITO_VERSION=${PROJECT_VERSION%.*} fi diff --git a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/src/main/resources/application.properties b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/src/main/resources/application.properties index 932e513803..0fb8c5fa1e 100644 --- a/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/src/main/resources/application.properties +++ b/kogito-quarkus-examples/process-usertasks-timer-quarkus-with-console/src/main/resources/application.properties @@ -62,8 +62,8 @@ kogito.jobs-service.url=http://localhost:8580 %postgresql.quarkus.datasource.username=kogito-user %postgresql.quarkus.datasource.password=kogito-pass %postgresql.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/kogito +%postgresql.kie.flyway.enabled=true %postgresql.quarkus.kogito.devservices.enabled=false -%postgresql.quarkus.flyway.migrate-at-start=true %infinispan.kogito.persistence.type=infinispan %infinispan.quarkus.infinispan-client.hosts=localhost:11222 diff --git a/kogito-quarkus-examples/process-usertasks-with-security-oidc-quarkus/src/test/java/org/acme/travels/ApprovalsProcessIT.java b/kogito-quarkus-examples/process-usertasks-with-security-oidc-quarkus/src/test/java/org/acme/travels/ApprovalsProcessIT.java index 2d4660efd7..5485991eaf 100644 --- a/kogito-quarkus-examples/process-usertasks-with-security-oidc-quarkus/src/test/java/org/acme/travels/ApprovalsProcessIT.java +++ b/kogito-quarkus-examples/process-usertasks-with-security-oidc-quarkus/src/test/java/org/acme/travels/ApprovalsProcessIT.java @@ -19,18 +19,15 @@ package org.acme.travels; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.jbpm.process.instance.impl.humantask.HumanTaskTransition; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.workitem.Complete; import org.junit.jupiter.api.Test; import org.kie.kogito.Model; import org.kie.kogito.auth.IdentityProviders; import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessInstance; import org.kie.kogito.process.WorkItem; @@ -42,6 +39,8 @@ import jakarta.inject.Inject; import jakarta.inject.Named; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -77,6 +76,7 @@ public void testApprovalProcess() { results.put("approved", true); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Arrays.asList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -118,9 +118,12 @@ public void testApprovalProcessViaPhases() { List workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", true), policy)); + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", true), policy)); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Arrays.asList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -131,8 +134,9 @@ public void testApprovalProcessViaPhases() { workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", false), policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", false), policy)); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); diff --git a/kogito-quarkus-examples/process-usertasks-with-security-quarkus/src/test/java/org/acme/travels/security/quarkus/ApprovalsProcessTest.java b/kogito-quarkus-examples/process-usertasks-with-security-quarkus/src/test/java/org/acme/travels/security/quarkus/ApprovalsProcessTest.java index fffafa26b6..7faa81a290 100644 --- a/kogito-quarkus-examples/process-usertasks-with-security-quarkus/src/test/java/org/acme/travels/security/quarkus/ApprovalsProcessTest.java +++ b/kogito-quarkus-examples/process-usertasks-with-security-quarkus/src/test/java/org/acme/travels/security/quarkus/ApprovalsProcessTest.java @@ -25,13 +25,11 @@ import org.acme.travels.Address; import org.acme.travels.Traveller; -import org.jbpm.process.instance.impl.humantask.HumanTaskTransition; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.workitem.Complete; import org.junit.jupiter.api.Test; import org.kie.kogito.Model; import org.kie.kogito.auth.IdentityProviders; import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessInstance; import org.kie.kogito.process.WorkItem; @@ -41,6 +39,8 @@ import jakarta.inject.Inject; import jakarta.inject.Named; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -75,6 +75,7 @@ public void testApprovalProcess() { results.put("approved", true); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -117,9 +118,12 @@ public void testApprovalProcessViaPhases() { List workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", true), policy)); + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", true), policy)); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -130,8 +134,9 @@ public void testApprovalProcessViaPhases() { workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", false), policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", false), policy)); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); diff --git a/kogito-springboot-examples/onboarding-springboot/src/main/java/org/kie/kogito/examples/WorkItemHandlerConfig.java b/kogito-springboot-examples/onboarding-springboot/src/main/java/org/kie/kogito/examples/WorkItemHandlerConfig.java index fc2f30843a..52a809ca0f 100644 --- a/kogito-springboot-examples/onboarding-springboot/src/main/java/org/kie/kogito/examples/WorkItemHandlerConfig.java +++ b/kogito-springboot-examples/onboarding-springboot/src/main/java/org/kie/kogito/examples/WorkItemHandlerConfig.java @@ -30,7 +30,7 @@ import org.kie.kogito.addons.k8s.LocalEndpointDiscovery; import org.kie.kogito.addons.springboot.k8s.workitems.SpringDiscoveredEndpointCaller; import org.kie.kogito.examples.onboarding.DecisionTaskWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.impl.DefaultWorkItemHandlerConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; diff --git a/kogito-springboot-examples/onboarding-springboot/src/main/java/org/kie/kogito/examples/onboarding/DecisionTaskWorkItemHandler.java b/kogito-springboot-examples/onboarding-springboot/src/main/java/org/kie/kogito/examples/onboarding/DecisionTaskWorkItemHandler.java index f958f4591a..81be4f66a2 100644 --- a/kogito-springboot-examples/onboarding-springboot/src/main/java/org/kie/kogito/examples/onboarding/DecisionTaskWorkItemHandler.java +++ b/kogito-springboot-examples/onboarding-springboot/src/main/java/org/kie/kogito/examples/onboarding/DecisionTaskWorkItemHandler.java @@ -19,14 +19,17 @@ package org.kie.kogito.examples.onboarding; import java.util.Map; +import java.util.Optional; import org.kie.kogito.addons.springboot.k8s.workitems.SpringDiscoveredEndpointCaller; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.WorkItemTransition; +import org.kie.kogito.process.workitems.impl.DefaultKogitoWorkItemHandler; import org.springframework.http.HttpMethod; -public class DecisionTaskWorkItemHandler implements KogitoWorkItemHandler { +public class DecisionTaskWorkItemHandler extends DefaultKogitoWorkItemHandler { private SpringDiscoveredEndpointCaller endpointCaller; @@ -35,15 +38,9 @@ public DecisionTaskWorkItemHandler(SpringDiscoveredEndpointCaller endpointCaller } @Override - public void executeWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { + public Optional activateWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { Map results = this.endpointCaller.discoverAndCall(workItem, System.getenv("NAMESPACE"), "Decision", HttpMethod.POST.toString()); - - manager.completeWorkItem(workItem.getStringId(), results); - } - - @Override - public void abortWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { - + return Optional.of(handler.completeTransition(workItem.getPhaseStatus(), results)); } @Override diff --git a/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/onboarding/OnboardingEndpointIT.java b/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/onboarding/OnboardingEndpointIT.java index 3cb334537e..920a89545a 100644 --- a/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/onboarding/OnboardingEndpointIT.java +++ b/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/onboarding/OnboardingEndpointIT.java @@ -31,8 +31,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.kie.kogito.examples.KogitoOnboardingApplication; import org.kie.kogito.examples.test.RecordedOutputWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.ProcessConfig; import org.kie.kogito.testcontainers.springboot.InfinispanSpringBootTestResource; import org.springframework.beans.factory.annotation.Autowired; diff --git a/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/test/RecordedOutputWorkItemHandler.java b/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/test/RecordedOutputWorkItemHandler.java index 05a6799916..f7559da0d9 100644 --- a/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/test/RecordedOutputWorkItemHandler.java +++ b/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/test/RecordedOutputWorkItemHandler.java @@ -20,26 +20,23 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.function.Function; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.WorkItemTransition; +import org.kie.kogito.process.workitems.impl.DefaultKogitoWorkItemHandler; -public class RecordedOutputWorkItemHandler implements KogitoWorkItemHandler { +public class RecordedOutputWorkItemHandler extends DefaultKogitoWorkItemHandler { private Map>> recorded = new HashMap<>(); @Override - public void executeWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { + public Optional activateWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workItem, WorkItemTransition transition) { Map results = recorded.remove(workItem.getParameter("TaskName")).apply(workItem); - - manager.completeWorkItem(workItem.getStringId(), results); - } - - @Override - public void abortWorkItem(KogitoWorkItem workItem, KogitoWorkItemManager manager) { - + return Optional.of(handler.completeTransition(workItem.getPhaseStatus(), results)); } public void record(String name, Function> item) { diff --git a/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/test/RecordedWorkItemHandlerConfig.java b/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/test/RecordedWorkItemHandlerConfig.java index 26b40467a3..ea4983a3ab 100644 --- a/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/test/RecordedWorkItemHandlerConfig.java +++ b/kogito-springboot-examples/onboarding-springboot/src/test/java/org/kie/kogito/examples/test/RecordedWorkItemHandlerConfig.java @@ -23,7 +23,7 @@ import java.util.Collection; import java.util.List; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.impl.DefaultWorkItemHandlerConfig; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; diff --git a/kogito-springboot-examples/process-postgresql-persistence-springboot/README.md b/kogito-springboot-examples/process-postgresql-persistence-springboot/README.md index bc76d6d71d..238fd4c17d 100644 --- a/kogito-springboot-examples/process-postgresql-persistence-springboot/README.md +++ b/kogito-springboot-examples/process-postgresql-persistence-springboot/README.md @@ -146,7 +146,7 @@ To make use of this application it is as simple as putting a sending request to Complete curl command can be found below: -``` +```bash curl -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' -d '{"name" : "my fancy deal", "traveller" : { "firstName" : "John", "lastName" : "Doe", "email" : "jon.doe@example.com", "nationality" : "American","address" : { "street" : "main street", "city" : "Boston", "zipCode" : "10005", "country" : "US" }}}' http://localhost:8080/deals ``` @@ -156,13 +156,13 @@ this will then trigger the review user task that you can work with. First you can display all active reviews of deals -``` +```bash curl -H 'Content-Type:application/json' -H 'Accept:application/json' http://localhost:8080/dealreviews ``` based on the response you can select one of the reviews to see more details -``` +```bash curl -H 'Content-Type:application/json' -H 'Accept:application/json' http://localhost:8080/dealreviews/{uuid}/tasks?user=john ``` diff --git a/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/docker-compose.yml b/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/docker-compose.yml index 8a810481bd..bc79f106f2 100644 --- a/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/docker-compose.yml +++ b/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/docker-compose.yml @@ -20,31 +20,41 @@ version: "3" services: - postgres-compose: - image: postgres:13.4-alpine3.14 - environment: - POSTGRES_PASSWORD: pass + postgres: + image: postgres:16.1-alpine3.19 ports: - 5432:5432 volumes: - - ${HOME}/postgresql/data:/var/lib/postgresql/data - ./sql:/docker-entrypoint-initdb.d/ + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres networks: - postgres-compose-network - container_name: postgres-container - pgadmin-compose: - image: dpage/pgadmin4:5.0 - environment: - PGADMIN_DEFAULT_EMAIL: user@user.org - PGADMIN_DEFAULT_PASSWORD: pass + pgadmin: + image: dpage/pgadmin4:8.2 ports: - 8055:80 depends_on: - - postgres-compose + - postgres + volumes: + - ./pgadmin/servers.json:/pgadmin4/servers.json + - ./pgadmin/pgpass:/pgadmin4/pgpass + entrypoint: > + /bin/sh -c " + cp -f /pgadmin4/pgpass /var/lib/pgadmin/; + chmod 600 /var/lib/pgadmin/pgpass; + /entrypoint.sh + " + environment: + PGADMIN_DEFAULT_EMAIL: user@kogito.org + PGADMIN_DEFAULT_PASSWORD: pass + PGADMIN_CONFIG_SERVER_MODE: "False" + PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: "False" + GUNICORN_ACCESS_LOGFILE: "/dev/null" networks: - postgres-compose-network - container_name: pgadmin-container networks: postgres-compose-network: diff --git a/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/pgadmin/pgpass b/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/pgadmin/pgpass new file mode 100644 index 0000000000..2e0fbd6a33 --- /dev/null +++ b/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/pgadmin/pgpass @@ -0,0 +1,2 @@ +postgres:5432:kogito:kogito-user:kogito-pass +postgres:5432:postgres:kogito-user:kogito-pass \ No newline at end of file diff --git a/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/pgadmin/servers.json b/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/pgadmin/servers.json new file mode 100644 index 0000000000..caafe268c0 --- /dev/null +++ b/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/pgadmin/servers.json @@ -0,0 +1,14 @@ +{ + "Servers": { + "1": { + "Name": "kogito", + "Group": "Servers", + "Host": "postgres", + "Port": 5432, + "MaintenanceDB": "kogito", + "Username": "kogito-user", + "SSLMode": "disable", + "PassFile": "/var/lib/pgadmin/pgpass" + } + } +} diff --git a/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/sql/init.sql b/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/sql/init.sql index 5b483ec23d..e9ceb0033b 100644 --- a/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/sql/init.sql +++ b/kogito-springboot-examples/process-postgresql-persistence-springboot/docker-compose/sql/init.sql @@ -5,7 +5,7 @@ CREATE ROLE "kogito-user" WITH CREATEDB CREATEROLE NOREPLICATION - ENCRYPTED PASSWORD 'md54adb613a8ffdd707e032c918d791e2e5'; + PASSWORD 'kogito-pass'; CREATE DATABASE kogito WITH diff --git a/kogito-springboot-examples/process-postgresql-persistence-springboot/src/main/resources/application.properties b/kogito-springboot-examples/process-postgresql-persistence-springboot/src/main/resources/application.properties index a3ac58a919..143f097075 100644 --- a/kogito-springboot-examples/process-postgresql-persistence-springboot/src/main/resources/application.properties +++ b/kogito-springboot-examples/process-postgresql-persistence-springboot/src/main/resources/application.properties @@ -20,8 +20,10 @@ server.address=0.0.0.0 #run create tables scripts during the application startup -spring.flyway.enabled=true -spring.flyway.locations=classpath:db/{vendor} +kie.flyway.enabled=true + +#Disabling Spring-Boot Flyway to avoid unnecessary Data Base initialization +spring.flyway.enabled=false #jdbc kogito.persistence.type=jdbc diff --git a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/config/CustomWorkItemHandlerConfig.java b/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/config/CustomWorkItemHandlerConfig.java index 3021d7685b..7727ba2c44 100644 --- a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/config/CustomWorkItemHandlerConfig.java +++ b/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/config/CustomWorkItemHandlerConfig.java @@ -18,8 +18,7 @@ */ package org.acme.travels.config; -import org.acme.travels.usertasks.CustomHumanTaskLifeCycle; -import org.jbpm.process.instance.impl.humantask.HumanTaskWorkItemHandler; +import org.acme.travels.usertasks.CustomHumanTaskWorkItemHandler; import org.kie.kogito.process.impl.DefaultWorkItemHandlerConfig; import org.springframework.stereotype.Component; @@ -36,6 +35,6 @@ @Component public class CustomWorkItemHandlerConfig extends DefaultWorkItemHandlerConfig { { - register("Human Task", new HumanTaskWorkItemHandler(new CustomHumanTaskLifeCycle())); + register("Human Task", new CustomHumanTaskWorkItemHandler()); } } \ No newline at end of file diff --git a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CompleteStartedOnly.java b/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CompleteStartedOnly.java deleted file mode 100644 index 7465bf0a4f..0000000000 --- a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CompleteStartedOnly.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.acme.travels.usertasks; - -import java.util.Arrays; -import java.util.List; - -import org.jbpm.process.instance.impl.workitem.Complete; -import org.kie.kogito.process.workitem.LifeCyclePhase; - -/** - * Extension to Complete life cycle phase that applies to any human task. - * It will set the status to "Completed" - * - * This phase will only allow to complete tasks that are in started phase. - * - * It can transition from - *
    - *
  • Start
  • - *
- * - * This is a terminating (final) phase. - */ -public class CompleteStartedOnly extends Complete { - - private List allowedTransitions = Arrays.asList(Start.ID); - - @Override - public boolean canTransition(LifeCyclePhase phase) { - return allowedTransitions.contains(phase.id()); - } - -} diff --git a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CustomHumanTaskLifeCycle.java b/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CustomHumanTaskLifeCycle.java deleted file mode 100644 index d5c0715617..0000000000 --- a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CustomHumanTaskLifeCycle.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.acme.travels.usertasks; - -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.jbpm.process.instance.impl.humantask.BaseHumanTaskLifeCycle; -import org.jbpm.process.instance.impl.humantask.InternalHumanTaskWorkItem; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.humantask.phases.Release; -import org.jbpm.process.instance.impl.humantask.phases.Skip; -import org.jbpm.process.instance.impl.workitem.Abort; -import org.jbpm.process.instance.impl.workitem.Active; -import org.jbpm.process.instance.impl.workitem.Complete; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; -import org.kie.kogito.internal.process.runtime.KogitoWorkItemManager; -import org.kie.kogito.process.workitem.InvalidLifeCyclePhaseException; -import org.kie.kogito.process.workitem.InvalidTransitionException; -import org.kie.kogito.process.workitem.LifeCycle; -import org.kie.kogito.process.workitem.LifeCyclePhase; -import org.kie.kogito.process.workitem.NotAuthorizedException; -import org.kie.kogito.process.workitem.Policy; -import org.kie.kogito.process.workitem.Transition; -import org.kie.kogito.process.workitems.InternalKogitoWorkItemManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Custom life cycle definition for human tasks. It comes with following phases - * - *
    - *
  • Active
  • - *
  • Claim
  • - *
  • Release
  • - *
  • Start
  • - *
  • Complete - extended one that allows to only complete started tasks
  • - *
  • Skip
  • - *
  • Abort
  • - *
- * At the beginning human task enters - * - *
- * Active
- * 
- * - * phase. From there it can go to - * - *
    - *
  • Claim
  • - *
  • Skip
  • - *
  • Abort
  • - *
- * - * at any time. At each phase data can be associated and by that set on work item. - * - * Completion can only be performed on started tasks. - */ -public class CustomHumanTaskLifeCycle implements LifeCycle> { - - private static final Logger logger = LoggerFactory.getLogger(BaseHumanTaskLifeCycle.class); - - private Map phases = new LinkedHashMap<>(); - - public CustomHumanTaskLifeCycle() { - phases.put(Claim.ID, new Claim()); - phases.put(Release.ID, new Release()); - phases.put(Start.ID, new Start()); - phases.put(Complete.ID, new CompleteStartedOnly()); - phases.put(Skip.ID, new Skip()); - phases.put(Active.ID, new Active()); - phases.put(Abort.ID, new Abort()); - } - - @Override - public LifeCyclePhase phaseById(String phaseId) { - return phases.get(phaseId); - } - - @Override - public Collection phases() { - return phases.values(); - } - - @Override - public Map transitionTo(KogitoWorkItem workItem, KogitoWorkItemManager manager, Transition> transition) { - logger.debug("Transition method invoked for work item {} to transition to {}, currently in phase {} and status {}", workItem.getStringId(), transition.phase(), workItem.getPhaseId(), - workItem.getPhaseStatus()); - - InternalHumanTaskWorkItem humanTaskWorkItem = (InternalHumanTaskWorkItem) workItem; - - LifeCyclePhase targetPhase = phases.get(transition.phase()); - if (targetPhase == null) { - logger.debug("Target life cycle phase '{}' does not exist in {}", transition.phase(), this.getClass().getSimpleName()); - throw new InvalidLifeCyclePhaseException(transition.phase()); - } - - LifeCyclePhase currentPhase = phases.get(humanTaskWorkItem.getPhaseId()); - - if (!targetPhase.canTransition(currentPhase)) { - logger.debug("Target life cycle phase '{}' cannot transition from current state '{}'", targetPhase.id(), currentPhase.id()); - throw new InvalidTransitionException("Cannot transition from " + humanTaskWorkItem.getPhaseId() + " to " + targetPhase.id()); - } - - if (!targetPhase.id().equals(Active.ID) && !targetPhase.id().equals(Abort.ID) && !humanTaskWorkItem.enforce(transition.policies().toArray(new Policy[transition.policies().size()]))) { - throw new NotAuthorizedException("User is not authorized to access task instance with id " + humanTaskWorkItem.getStringId()); - } - - humanTaskWorkItem.setPhaseId(targetPhase.id()); - humanTaskWorkItem.setPhaseStatus(targetPhase.status()); - - targetPhase.apply(humanTaskWorkItem, transition); - if (transition.data() != null) { - logger.debug("Updating data for work item {}", targetPhase.id(), humanTaskWorkItem.getStringId()); - humanTaskWorkItem.getResults().putAll(transition.data()); - } - logger.debug("Transition for work item {} to {} done, currently in phase {} and status {}", workItem.getStringId(), transition.phase(), workItem.getPhaseId(), workItem.getPhaseStatus()); - - if (targetPhase.isTerminating()) { - logger.debug("Target life cycle phase '{}' is terminiating, completing work item {}", targetPhase.id(), humanTaskWorkItem.getStringId()); - // since target life cycle phase is terminating completing work item - ((InternalKogitoWorkItemManager) manager).internalCompleteWorkItem(humanTaskWorkItem); - } - - return data(humanTaskWorkItem); - } - - @Override - public Map data(KogitoWorkItem workItem) { - return ((InternalHumanTaskWorkItem) workItem).getResults(); - } -} diff --git a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CustomHumanTaskWorkItemHandler.java b/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CustomHumanTaskWorkItemHandler.java new file mode 100644 index 0000000000..aa22513441 --- /dev/null +++ b/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CustomHumanTaskWorkItemHandler.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.acme.travels.usertasks; + +import java.util.Optional; + +import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemManager; +import org.kie.kogito.internal.process.workitem.WorkItemLifeCycle; +import org.kie.kogito.internal.process.workitem.WorkItemPhaseState; +import org.kie.kogito.internal.process.workitem.WorkItemTerminationType; +import org.kie.kogito.internal.process.workitem.WorkItemTransition; +import org.kie.kogito.process.workitems.impl.DefaultKogitoWorkItemHandler; +import org.kie.kogito.process.workitems.impl.DefaultWorkItemLifeCycle; +import org.kie.kogito.process.workitems.impl.DefaultWorkItemLifeCyclePhase; + +public class CustomHumanTaskWorkItemHandler extends DefaultKogitoWorkItemHandler { + + public static final String TRANSITION_COMPLETE = "complete"; + public static final String TRANSITION_ABORT = "abort"; + public static final String TRANSITION_ACTIVATE = "activate"; + public static final String TRANSITION_START = "start"; + public static final String TRANSITION_SKIP = "skip"; + + @Override + public WorkItemLifeCycle initialize() { + WorkItemPhaseState initialized = WorkItemPhaseState.initialized(); + WorkItemPhaseState completed = WorkItemPhaseState.of("Completed", WorkItemTerminationType.COMPLETE); + WorkItemPhaseState aborted = WorkItemPhaseState.of("Aborted", WorkItemTerminationType.ABORT); + WorkItemPhaseState activated = WorkItemPhaseState.of("Activated"); + WorkItemPhaseState started = WorkItemPhaseState.of("Started"); + + DefaultWorkItemLifeCyclePhase active = new DefaultWorkItemLifeCyclePhase(TRANSITION_ACTIVATE, initialized, activated, this::activateWorkItemHandler); + DefaultWorkItemLifeCyclePhase start = new DefaultWorkItemLifeCyclePhase(TRANSITION_START, activated, started, this::activateWorkItemHandler); + DefaultWorkItemLifeCyclePhase complete = new DefaultWorkItemLifeCyclePhase(TRANSITION_COMPLETE, started, completed, this::completeWorkItemHandler); + DefaultWorkItemLifeCyclePhase abort = new DefaultWorkItemLifeCyclePhase(TRANSITION_ABORT, started, aborted, this::abortWorkItemHandler); + + return new DefaultWorkItemLifeCycle(active, start, abort, complete); + } + + @Override + public Optional completeWorkItemHandler(KogitoWorkItemManager manager, KogitoWorkItemHandler handler, KogitoWorkItem workitem, WorkItemTransition transition) { + getUserFromTransition(transition).ifPresent(e -> workitem.setOutput("ActorId", e)); + return Optional.empty(); + } + + private Optional getUserFromTransition(WorkItemTransition transition) { + Optional securityPolicy = transition.policies().stream().filter(SecurityPolicy.class::isInstance).map(SecurityPolicy.class::cast).findAny(); + if (securityPolicy.isPresent()) { + return Optional.ofNullable(securityPolicy.get().getUser()); + } + return Optional.empty(); + } +} diff --git a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/Start.java b/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/Start.java deleted file mode 100644 index 7a5199de1c..0000000000 --- a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/Start.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.acme.travels.usertasks; - -import java.util.Arrays; -import java.util.List; - -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.humantask.phases.Release; -import org.jbpm.process.instance.impl.workitem.Active; -import org.kie.kogito.process.workitem.LifeCyclePhase; - -/** - * Start life cycle phase that applies to any human task. - * It will set the status to "Started" - * - * It can transition from - *
    - *
  • Active
  • - *
  • Claim
  • - *
  • Release
  • - *
- * - */ -public class Start implements LifeCyclePhase { - - public static final String ID = "start"; - public static final String STATUS = "Started"; - - private List allowedTransitions = Arrays.asList(Active.ID, Claim.ID, Release.ID); - - @Override - public String id() { - return ID; - } - - @Override - public String status() { - return STATUS; - } - - @Override - public boolean isTerminating() { - return false; - } - - @Override - public boolean canTransition(LifeCyclePhase phase) { - return allowedTransitions.contains(phase.id()); - } -} diff --git a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/test/java/org/acme/travels/custom/lifecycle/springboot/ApprovalsProcessTest.java b/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/test/java/org/acme/travels/custom/lifecycle/springboot/ApprovalsProcessTest.java index 4b5af8bfd8..e761d10a67 100644 --- a/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/test/java/org/acme/travels/custom/lifecycle/springboot/ApprovalsProcessTest.java +++ b/kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/test/java/org/acme/travels/custom/lifecycle/springboot/ApprovalsProcessTest.java @@ -25,19 +25,16 @@ import org.acme.travels.Address; import org.acme.travels.Traveller; -import org.acme.travels.usertasks.Start; -import org.jbpm.process.instance.impl.humantask.HumanTaskTransition; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.workitem.Complete; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.kie.kogito.Model; import org.kie.kogito.auth.IdentityProviders; import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.InvalidTransitionException; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessInstance; import org.kie.kogito.process.WorkItem; -import org.kie.kogito.process.workitem.InvalidTransitionException; import org.kie.kogito.tests.KogitoInfinispanSpringbootApplication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -46,6 +43,8 @@ import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.junit.jupiter.SpringExtension; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; @@ -73,7 +72,7 @@ public void testApprovalProcess() { processInstance.start(); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_ACTIVE, processInstance.status()); - SecurityPolicy policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("managers"))); + SecurityPolicy policy = SecurityPolicy.of(IdentityProviders.of("admin", singletonList("managers"))); processInstance.workItems(policy); @@ -81,13 +80,15 @@ public void testApprovalProcess() { assertEquals(1, workItems.size()); Map results = new HashMap<>(); results.put("approved", true); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Start.ID, null, policy)); + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("start", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); + policy = SecurityPolicy.of(IdentityProviders.of("admin", singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); - policy = SecurityPolicy.of(IdentityProviders.of("john", Collections.singletonList("managers"))); + policy = SecurityPolicy.of(IdentityProviders.of("john", singletonList("managers"))); processInstance.workItems(policy); @@ -95,7 +96,7 @@ public void testApprovalProcess() { assertEquals(1, workItems.size()); results.put("approved", false); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Start.ID, null, policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("start", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); @@ -120,7 +121,7 @@ public void testApprovalProcessViaPhases() { processInstance.start(); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_ACTIVE, processInstance.status()); - SecurityPolicy policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("managers"))); + SecurityPolicy policy = SecurityPolicy.of(IdentityProviders.of("admin", singletonList("managers"))); List workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); @@ -128,24 +129,26 @@ public void testApprovalProcessViaPhases() { final String wiId = workItems.get(0).getId(); // test to make sure you can't complete if the task is not in started state + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + try { - processInstance.transitionWorkItem(wiId, new HumanTaskTransition(Complete.ID, - Collections.singletonMap("approved", true), - SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("managers"))))); + processInstance.transitionWorkItem(wiId, handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", true), + SecurityPolicy.of(IdentityProviders.of("admin", singletonList("managers"))))); fail("It's not possible to complete non started tasks"); } catch (InvalidTransitionException e) { // expected } // now test going through phases - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Start.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", true), policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("start", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", true), policy)); + policy = SecurityPolicy.of(IdentityProviders.of("admin", singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); - policy = SecurityPolicy.of(IdentityProviders.of("john", Collections.singletonList("managers"))); + policy = SecurityPolicy.of(IdentityProviders.of("john", singletonList("managers"))); processInstance.workItems(policy); @@ -153,8 +156,9 @@ public void testApprovalProcessViaPhases() { assertEquals(1, workItems.size()); // test that claim can be skipped - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Start.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", false), policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("start", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", false), policy)); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); diff --git a/kogito-springboot-examples/process-usertasks-springboot/src/test/java/org/acme/travels/springboot/ApprovalsProcessTest.java b/kogito-springboot-examples/process-usertasks-springboot/src/test/java/org/acme/travels/springboot/ApprovalsProcessTest.java index 9ec367111b..4258f6a1da 100644 --- a/kogito-springboot-examples/process-usertasks-springboot/src/test/java/org/acme/travels/springboot/ApprovalsProcessTest.java +++ b/kogito-springboot-examples/process-usertasks-springboot/src/test/java/org/acme/travels/springboot/ApprovalsProcessTest.java @@ -25,14 +25,12 @@ import org.acme.travels.Address; import org.acme.travels.Traveller; -import org.jbpm.process.instance.impl.humantask.HumanTaskTransition; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.workitem.Complete; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.kie.kogito.Model; import org.kie.kogito.auth.IdentityProviders; import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessInstance; import org.kie.kogito.process.WorkItem; @@ -72,21 +70,18 @@ public void testApprovalProcess() { SecurityPolicy policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("managers"))); - processInstance.workItems(policy); - List workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); Map results = new HashMap<>(); results.put("approved", true); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); policy = SecurityPolicy.of(IdentityProviders.of("john", Collections.singletonList("managers"))); - processInstance.workItems(policy); - workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); @@ -122,9 +117,12 @@ public void testApprovalProcessViaPhases() { List workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", true), policy)); + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), Collections.singletonMap("approved", true), policy)); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -135,8 +133,9 @@ public void testApprovalProcessViaPhases() { workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", false), policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), Collections.emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), Collections.singletonMap("approved", false), policy)); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); diff --git a/kogito-springboot-examples/process-usertasks-with-security-oidc-springboot/src/test/java/org/acme/travels/security/oidc/springboot/ApprovalsProcessTest.java b/kogito-springboot-examples/process-usertasks-with-security-oidc-springboot/src/test/java/org/acme/travels/security/oidc/springboot/ApprovalsProcessTest.java index fa25b9e3d3..8ac6708233 100644 --- a/kogito-springboot-examples/process-usertasks-with-security-oidc-springboot/src/test/java/org/acme/travels/security/oidc/springboot/ApprovalsProcessTest.java +++ b/kogito-springboot-examples/process-usertasks-with-security-oidc-springboot/src/test/java/org/acme/travels/security/oidc/springboot/ApprovalsProcessTest.java @@ -25,14 +25,12 @@ import org.acme.travels.Address; import org.acme.travels.Traveller; -import org.jbpm.process.instance.impl.humantask.HumanTaskTransition; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.workitem.Complete; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.kie.kogito.Model; import org.kie.kogito.auth.IdentityProviders; import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessInstance; import org.kie.kogito.process.WorkItem; @@ -44,6 +42,8 @@ import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.junit.jupiter.SpringExtension; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -80,6 +80,7 @@ public void testApprovalProcess() { results.put("approved", true); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -122,9 +123,12 @@ public void testApprovalProcessViaPhases() { List workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", true), policy)); + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", true), policy)); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -135,8 +139,9 @@ public void testApprovalProcessViaPhases() { workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", false), policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", false), policy)); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); diff --git a/kogito-springboot-examples/process-usertasks-with-security-springboot/src/test/java/org/acme/travels/security/springboot/ApprovalsProcessTest.java b/kogito-springboot-examples/process-usertasks-with-security-springboot/src/test/java/org/acme/travels/security/springboot/ApprovalsProcessTest.java index 2a1467f4d8..5f56251379 100644 --- a/kogito-springboot-examples/process-usertasks-with-security-springboot/src/test/java/org/acme/travels/security/springboot/ApprovalsProcessTest.java +++ b/kogito-springboot-examples/process-usertasks-with-security-springboot/src/test/java/org/acme/travels/security/springboot/ApprovalsProcessTest.java @@ -25,14 +25,12 @@ import org.acme.travels.Address; import org.acme.travels.Traveller; -import org.jbpm.process.instance.impl.humantask.HumanTaskTransition; -import org.jbpm.process.instance.impl.humantask.phases.Claim; -import org.jbpm.process.instance.impl.workitem.Complete; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.kie.kogito.Model; import org.kie.kogito.auth.IdentityProviders; import org.kie.kogito.auth.SecurityPolicy; +import org.kie.kogito.internal.process.workitem.KogitoWorkItemHandler; import org.kie.kogito.process.Process; import org.kie.kogito.process.ProcessInstance; import org.kie.kogito.process.WorkItem; @@ -44,6 +42,8 @@ import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.junit.jupiter.SpringExtension; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -80,6 +80,7 @@ public void testApprovalProcess() { results.put("approved", true); processInstance.completeWorkItem(workItems.get(0).getId(), results, policy); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -122,9 +123,12 @@ public void testApprovalProcessViaPhases() { List workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", true), policy)); + KogitoWorkItemHandler handler = approvalsProcess.getKogitoWorkItemHandler(workItems.get(0).getWorkItemHandlerName()); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", true), policy)); + policy = SecurityPolicy.of(IdentityProviders.of("admin", Collections.singletonList("mgmt"))); workItems = processInstance.workItems(policy); assertEquals(0, workItems.size()); @@ -135,8 +139,9 @@ public void testApprovalProcessViaPhases() { workItems = processInstance.workItems(policy); assertEquals(1, workItems.size()); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Claim.ID, null, policy)); - processInstance.transitionWorkItem(workItems.get(0).getId(), new HumanTaskTransition(Complete.ID, Collections.singletonMap("approved", false), policy)); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("claim", workItems.get(0).getPhaseStatus(), emptyMap(), policy)); + workItems = processInstance.workItems(policy); + processInstance.transitionWorkItem(workItems.get(0).getId(), handler.newTransition("complete", workItems.get(0).getPhaseStatus(), singletonMap("approved", false), policy)); assertEquals(org.kie.api.runtime.process.ProcessInstance.STATE_COMPLETED, processInstance.status()); diff --git a/serverless-workflow-examples/pom.xml b/serverless-workflow-examples/pom.xml index 962cbd298a..c9bb9cf6f8 100644 --- a/serverless-workflow-examples/pom.xml +++ b/serverless-workflow-examples/pom.xml @@ -49,6 +49,7 @@ serverless-workflow-compensation-quarkus serverless-workflow-consuming-events-over-http-quarkus serverless-workflow-correlation-quarkus + serverless-workflow-correlation-quarkus-mongodb serverless-workflow-custom-function-knative serverless-workflow-custom-type serverless-workflow-data-index-persistence-addon-quarkus diff --git a/serverless-workflow-examples/serverless-workflow-callback-events-over-http-quarkus/callback-workflow/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-callback-events-over-http-quarkus/callback-workflow/src/main/resources/application.properties index b01f42ee59..d5feef9860 100644 --- a/serverless-workflow-examples/serverless-workflow-callback-events-over-http-quarkus/callback-workflow/src/main/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-callback-events-over-http-quarkus/callback-workflow/src/main/resources/application.properties @@ -29,8 +29,9 @@ quarkus.rest-client.callback_yaml.url=http://localhost:8181/ kogito.persistence.type=jdbc kogito.persistence.proto.marshaller=false quarkus.datasource.db-kind=postgresql + #run create tables scripts -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true quarkus.native.native-image-xmx=8g diff --git a/serverless-workflow-examples/serverless-workflow-callback-quarkus/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-callback-quarkus/src/main/resources/application.properties index 05736d7b90..58758db2d8 100644 --- a/serverless-workflow-examples/serverless-workflow-callback-quarkus/src/main/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-callback-quarkus/src/main/resources/application.properties @@ -61,8 +61,9 @@ mp.messaging.outgoing.kogito-processdefinitions-events.value.serializer=org.apac kogito.persistence.type=jdbc quarkus.datasource.db-kind=postgresql kogito.persistence.proto.marshaller=false + #run create tables scripts -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true quarkus.native.native-image-xmx=8g diff --git a/serverless-workflow-examples/serverless-workflow-callback-quarkus/src/test/resources/application.properties b/serverless-workflow-examples/serverless-workflow-callback-quarkus/src/test/resources/application.properties index abb20a3c7f..aa62062ff2 100644 --- a/serverless-workflow-examples/serverless-workflow-callback-quarkus/src/test/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-callback-quarkus/src/test/resources/application.properties @@ -19,5 +19,5 @@ quarkus.kogito.devservices.enabled=false -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true quarkus.datasource.db-kind=postgresql diff --git a/serverless-workflow-examples/serverless-workflow-compensation-quarkus/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-compensation-quarkus/src/main/resources/application.properties index 34043ef3dd..654ba0b374 100644 --- a/serverless-workflow-examples/serverless-workflow-compensation-quarkus/src/main/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-compensation-quarkus/src/main/resources/application.properties @@ -22,7 +22,7 @@ quarkus.native.native-image-xmx=8g %persistence.quarkus.devservices.enabled=false -%persistence.quarkus.flyway.migrate-at-start=true +%persistence.kie.flyway.enabled=true %persistence.quarkus.datasource.db-kind=postgresql # profile to pack this example into a container, to use it execute activate the maven container profile, -Dcontainer diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/README.md b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/README.md new file mode 100644 index 0000000000..d901964f75 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/README.md @@ -0,0 +1,154 @@ +# Kogito Serverless Workflow - Correlation with Callback Example + +## Description + +This example contains a workflow service to demonstrate correlation feature using callback states and events. +Each callback state withing the workflow publishes an event and wait for a response event, +there is an incoming event, it is matched with the proper workflow instance by using the correlation attribute, in this case it is the `userid`. So for every incoming event the userid is used to properly find and trigger the proper workflow instance. The correlation is defined in the [workflow definition file](src/main/resources/correlation.sw.json) that is described using JSON format as defined in the [CNCF Serverless Workflow specification](https://github.com/serverlessworkflow/specification). + +```json +"correlation": [ + { + "contextAttributeName": "userid" + } +] +``` +Events should be in CloudEvent format and the correlation attribute should be defined as an extension attribute, in this case `userid`. + +The workflow example is started by events as well, so a start event should be published with the same correlation attribute `userid, that will be used to match correlations for the started workflow instance. + +In the example the event broker used to publish/receive the events is Kafka, and the used topics are the same described as the event types in the workflow definition. + + +```json +{ + "name": "newAccountEvent", + "source": "", + "type": "newAccountEventType", + "correlation": [ + { + "contextAttributeName": "userid" + } + ] +} +``` +For simplicity, the events are published and consumed in the same application running the workflow, but in a real use case they should come from different services interacting with the workflow, see [EventsService](src/main/java/org/kie/kogito/examples/EventsService.java). + +To start the workflow as mentioned, it is required an event to be published which is going to be consumed by the workflow service starting a new instance. A helper REST endpoint was recreated to simplify this step, so once a POST request is received it publishes the start event to the broker see [WorkflowResource](src/main/java/org/kie/kogito/examples/WorkflowResource.java). + +All eventing configuration and the broker parameters are in done in the [application.properties](src/main/resources/application.properties). + +## Infrastructure requirements + +### Kafka + +This quickstart requires an Apache Kafka to be available and by default expects it to be on default port and localhost. + +* Install and Startup Kafka Server / Zookeeper + +https://kafka.apache.org/quickstart + +To publish and consume the event, topic "move" is used. + +Optionally and for convenience, a docker-compose [configuration file](docker-compose/docker-compose.yml) is +provided in the path [docker-compose/](docker-compose/), where you can just run the command from there: + +```sh +docker-compose up +``` + +In this way a container for Kafka will be started on port 9092. + +### MongoDB + +Alternatively, you can run this example using persistence with a MongoDB server. + +Configuration for setting up the connection can be found in [applications.properties](src/main/resources/application.properties) file, which +follows the Quarkus MongoDB Client settings, for more information please check [MongoDB Client Configuration Reference](https://quarkus.io/guides/mongodb#configuration-reference). + +Optionally and for convenience, a docker-compose [configuration file](docker-compose/docker-compose.yml) is +provided in the path [docker-compose/](docker-compose/), where you can just run the command from there: + +```sh +docker-compose up +``` + +## Installing and Running + +### Prerequisites + +You will need: + - Java 17+ installed + - Environment variable JAVA_HOME set accordingly + - Maven 3.9.6+ installed + +When using native image compilation, you will also need: + - [GraalVm](https://www.graalvm.org/downloads/) 19.3.1+ installed + - Environment variable GRAALVM_HOME set accordingly + - Note that GraalVM native image compilation typically requires other packages (glibc-devel, zlib-devel and gcc) to be installed too. You also need 'native-image' installed in GraalVM (using 'gu install native-image'). Please refer to [GraalVM installation documentation](https://www.graalvm.org/docs/reference-manual/aot-compilation/#prerequisites) for more details. + +### Compile and Run in Local Dev Mode + +```sh +mvn clean package quarkus:dev +``` + +### Compile and Run in JVM mode + +```sh +mvn clean package +java -jar target/quarkus-app/quarkus-run.jar +``` + +or on Windows + +```sh +mvn clean package +java -jar target\quarkus-app\quarkus-run.jar +``` + +### Compile and Run in JVM mode using PostgreSQL persistence + +To enable persistence, please append `-Ppersistence` to your Maven command. +That will ensure the correct dependencies are in place, and automatically set the required properties to connect +with the PostgreSQL instance from the provided docker compose. + +```sh +mvn clean package -Peristence +``` + +### Compile and Run using Local Native Image +Note that this requires GRAALVM_HOME to point to a valid GraalVM installation + +```sh +mvn clean package -Pnative +``` + +To run the generated native executable, generated in `target/`, execute + +```sh +./target/serverless-workflow-correlation-quarkus-{version}-runner +``` + +### Start a workflow + +The service based on the JSON workflow definition can be access by sending a request to http://localhost:8080/account/{userid} + +Complete curl command can be found below: + +```sh +curl -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' http://localhost:8080/account/12345 +``` + +After a while (note that to you need give time for event to be consumed) you should see the log message printed in the console, and the workflow is completed. + +```text +2022-05-12 11:02:15,891 INFO [org.kie.kog.ser.eve.imp.ProcessEventDispatcher] (kogito-event-executor-0) Starting new process instance with signal 'newAccountEventType' +2022-05-12 11:02:18,909 INFO [io.sma.rea.mes.kafka] (vert.x-eventloop-thread-9) SRMSG18256: Initialize record store for topic-partition 'validateAccountEmail-0' at position 16. +2022-05-12 11:02:18,919 INFO [org.kie.kog.exa.EventsService] (pool-1-thread-1) Validate Account received. Workflow data JsonCloudEventData{node={"email":"test@test.com","userId":"12345"}} +2022-05-12 11:02:19,931 INFO [io.sma.rea.mes.kafka] (vert.x-eventloop-thread-5) SRMSG18256: Initialize record store for topic-partition 'validatedAccountEmail-0' at position 16. +2022-05-12 11:02:20,962 INFO [io.sma.rea.mes.kafka] (vert.x-eventloop-thread-8) SRMSG18256: Initialize record store for topic-partition 'activateAccount-0' at position 16. +2022-05-12 11:02:20,971 INFO [org.kie.kog.exa.EventsService] (pool-1-thread-1) Activate Account received. Workflow data JsonCloudEventData{node={"email":"test@test.com","userId":"12345"}} +2022-05-12 11:02:21,994 INFO [io.sma.rea.mes.kafka] (vert.x-eventloop-thread-6) SRMSG18256: Initialize record store for topic-partition 'activatedAccount-0' at position 7. +2022-05-12 11:02:22,006 INFO [org.kie.kog.exa.EventsService] (kogito-event-executor-0) Complete Account Creation received. Workflow data {"email":"test@test.com","userId":"12345"}, KogitoProcessInstanceId 0cef0eef-06c8-4433-baea-505fa8d45f68 +``` \ No newline at end of file diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/docker-compose/docker-compose.yml b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/docker-compose/docker-compose.yml new file mode 100644 index 0000000000..24ea2caf84 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/docker-compose/docker-compose.yml @@ -0,0 +1,85 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +version: "3" + +services: + zookeeper: + container_name: zookeeper + image: strimzi/kafka:0.20.1-kafka-2.6.0 + command: [ + "sh", "-c", + "bin/zookeeper-server-start.sh config/zookeeper.properties" + ] + ports: + - "2181:2181" + environment: + LOG_DIR: "/tmp/logs" + + kafka: + image: strimzi/kafka:0.20.1-kafka-2.6.0 + container_name: kafka + command: [ + "sh", "-c", + "bin/kafka-server-start.sh config/server.properties --override inter.broker.listener.name=$${KAFKA_INTER_BROKER_LISTENER_NAME} --override listener.security.protocol.map=$${KAFKA_LISTENER_SECURITY_PROTOCOL_MAP} --override listeners=$${KAFKA_LISTENERS} --override advertised.listeners=$${KAFKA_ADVERTISED_LISTENERS} --override zookeeper.connect=$${KAFKA_ZOOKEEPER_CONNECT}" + ] + depends_on: + - zookeeper + ports: + - "9092:9092" + environment: + KAFKA_BROKER_ID: 0 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + KAFKA_LISTENERS: INTERNAL://kafka:29092,EXTERNAL://kafka:9092 + KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:29092,EXTERNAL://localhost:9092 + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT + KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL + KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + LOG_DIR: "/tmp/logs" + + mongodb: + image: mongo:latest + restart: always + container_name: mongo + ports: + - "27017:27017" + networks: + - mongodb-compose-network + mongo-express: + image: mongo-express:latest + container_name: mongo_express + environment: + ME_CONFIG_MONGODB_ADMINUSERNAME: root + ME_CONFIG_MONGODB_ADMINPASSWORD: example + ME_CONFIG_MONGODB_URL: mongodb://mongo:27017/ + ME_CONFIG_BASICAUTH: false + ports: + - "8081:8081" + depends_on: + - mongodb + networks: + - mongodb-compose-network + +networks: + mongodb-compose-network: + driver: bridge + + +# curl -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' http://localhost:8888/account/mirror && curl -X POST -H 'Content-Type:application/json' -H 'Accept:application/json' http://localhost:8080/account/mirror \ No newline at end of file diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/pom.xml b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/pom.xml new file mode 100644 index 0000000000..07e78a31dc --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/pom.xml @@ -0,0 +1,199 @@ + + + + 4.0.0 + + + org.kie.kogito.examples + serverless-workflow-examples-parent + 999-SNAPSHOT + ../serverless-workflow-examples-parent/pom.xml + + + org.kie.kogito.examples + serverless-workflow-correlation-quarkus-mongodb + 1.0-SNAPSHOT + + Kogito Example :: Serverless Workflow Correlation :: Quarkus :: MongoDB + Kogito Serverless Workflow Correlation Example - Quarkus - MongoDB + + 3.8.4 + quarkus-bom + io.quarkus + 3.8.4 + org.kie.kogito + kogito-bom + 999-SNAPSHOT + 3.8.1 + 17 + 3.0.0-M7 + + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + ${kogito.bom.group-id} + ${kogito.bom.artifact-id} + ${kogito.bom.version} + pom + import + + + + + + org.apache.kie.sonataflow + sonataflow-quarkus + + + org.kie + kie-addons-quarkus-messaging + + + io.quarkus + quarkus-smallrye-reactive-messaging-kafka + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-resteasy-jackson + + + io.quarkus + quarkus-smallrye-health + + + org.kie + kie-addons-quarkus-source-files + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + org.awaitility + awaitility + test + + + + + ${project.artifactId} + + + maven-compiler-plugin + ${version.compiler.plugin} + + ${maven.compiler.release} + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus-plugin.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-failsafe-plugin + ${version.failsafe.plugin} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + integration-test + verify + + + + + + + + + container + + + container + + + + container + + + + io.quarkus + quarkus-container-image-jib + + + + + persistence + + + persistence + + + + + org.kie + kie-addons-quarkus-persistence-mongodb + + + io.quarkus + quarkus-mongodb-client + + + + + diff --git a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CompleteStartedOnly.java b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/java/org/kie/kogito/examples/Account.java similarity index 52% rename from kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CompleteStartedOnly.java rename to serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/java/org/kie/kogito/examples/Account.java index 7465bf0a4f..5da1f57541 100644 --- a/kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CompleteStartedOnly.java +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/java/org/kie/kogito/examples/Account.java @@ -16,34 +16,26 @@ * specific language governing permissions and limitations * under the License. */ -package org.acme.travels.usertasks; +package org.kie.kogito.examples; -import java.util.Arrays; -import java.util.List; +public class Account { -import org.jbpm.process.instance.impl.workitem.Complete; -import org.kie.kogito.process.workitem.LifeCyclePhase; + private String email; + private String userId; -/** - * Extension to Complete life cycle phase that applies to any human task. - * It will set the status to "Completed" - * - * This phase will only allow to complete tasks that are in started phase. - * - * It can transition from - *
    - *
  • Start
  • - *
- * - * This is a terminating (final) phase. - */ -public class CompleteStartedOnly extends Complete { + public Account() { + } - private List allowedTransitions = Arrays.asList(Start.ID); + public Account(String email, String userId) { + this.email = email; + this.userId = userId; + } - @Override - public boolean canTransition(LifeCyclePhase phase) { - return allowedTransitions.contains(phase.id()); + public String getEmail() { + return email; } + public String getUserId() { + return userId; + } } diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/java/org/kie/kogito/examples/EventsService.java b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/java/org/kie/kogito/examples/EventsService.java new file mode 100644 index 0000000000..004e81d958 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/java/org/kie/kogito/examples/EventsService.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.kie.kogito.examples; + +import java.net.URI; +import java.time.OffsetDateTime; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.eclipse.microprofile.reactive.messaging.Acknowledgment; +import org.eclipse.microprofile.reactive.messaging.Acknowledgment.Strategy; +import org.eclipse.microprofile.reactive.messaging.Incoming; +import org.eclipse.microprofile.reactive.messaging.Message; +import org.eclipse.microprofile.reactive.messaging.Outgoing; +import org.kie.kogito.event.cloudevents.utils.CloudEventUtils; +import org.kie.kogito.internal.process.runtime.KogitoProcessContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.cloudevents.CloudEvent; +import io.cloudevents.core.builder.CloudEventBuilder; +import io.cloudevents.jackson.JsonCloudEventData; + +@ApplicationScoped +public class EventsService { + + private static final Logger logger = LoggerFactory.getLogger(EventsService.class); + + @Inject + ObjectMapper objectMapper; + + private Map accounts = new ConcurrentHashMap<>(); + + public void complete(JsonNode workflowData, KogitoProcessContext context) { + logger.info("Complete Account Creation received. Workflow data {}, KogitoProcessInstanceId {} ", workflowData, context.getProcessInstance().getStringId()); + } + + @Incoming("validate") + @Outgoing("validated") + @Acknowledgment(Strategy.POST_PROCESSING) + public String onEventValidate(Message message) { + Optional ce = CloudEventUtils.decode(message.getPayload()); + JsonCloudEventData cloudEventData = (JsonCloudEventData) ce.get().getData(); + logger.info("Validate Account received. Workflow data {}", cloudEventData); + String userId = ce.get().getExtension("userid").toString(); + + //just for testing + accounts.put(userId, ce.get().getExtension("kogitoprocinstanceid").toString()); + + return generateCloudEvent(userId, "validatedAccountEmail", null); + } + + @Incoming("activate") + @Outgoing("activated") + @Acknowledgment(Strategy.POST_PROCESSING) + public String onEventActivate(Message message) { + Optional ce = CloudEventUtils.decode(message.getPayload()); + JsonCloudEventData cloudEventData = (JsonCloudEventData) ce.get().getData(); + logger.info("Activate Account received. Workflow data {}", cloudEventData); + return generateCloudEvent(ce.get().getExtension("userid").toString(), "activatedAccount", null); + } + + private String generateCloudEvent(String id, String type, Object data) { + try { + return objectMapper.writeValueAsString(CloudEventBuilder.v1() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("")) + .withType(type) + .withTime(OffsetDateTime.now()) + .withExtension("userid", id) + .withData(objectMapper.writeValueAsBytes(data)) + .build()); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException(e); + } + } + + public final String getAccount(String userId) { + return accounts.get(userId); + } +} diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/java/org/kie/kogito/examples/WorkflowResource.java b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/java/org/kie/kogito/examples/WorkflowResource.java new file mode 100644 index 0000000000..de6af279ab --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/java/org/kie/kogito/examples/WorkflowResource.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.kie.kogito.examples; + +import java.net.URI; +import java.time.OffsetDateTime; +import java.util.Collections; +import java.util.Map; +import java.util.UUID; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.core.Response; + +import org.eclipse.microprofile.reactive.messaging.Channel; +import org.eclipse.microprofile.reactive.messaging.Emitter; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.cloudevents.core.builder.CloudEventBuilder; + +/** + * Helper class used to facilitate testing using REST + */ +@Path("/account") +public class WorkflowResource { + + @Inject + ObjectMapper objectMapper; + + @Channel("start") + Emitter emitter; + + @Inject + EventsService eventsService; + + @POST + @Path("/{userId}") + public Response onEvent(@PathParam("userId") String userId) { + String start = generateCloudEvent(userId, "newAccountEventType"); + emitter.send(start); + return Response.status(Response.Status.CREATED).build(); + } + + @GET + @Path("/{userId}") + public Map getProcessInstanceId(@PathParam("userId") String userId) { + return Collections.singletonMap("processInstanceId", eventsService.getAccount(userId)); + } + + private String generateCloudEvent(String id, String type) { + try { + return objectMapper.writeValueAsString(CloudEventBuilder.v03() + .withId(UUID.randomUUID().toString()) + .withSource(URI.create("")) + .withType(type) + .withTime(OffsetDateTime.now()) + .withExtension("userid", id) + .withData(objectMapper.writeValueAsBytes(new Account("test@test.com", id))) + .build()); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException(e); + } + } +} diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/resources/application.properties new file mode 100644 index 0000000000..2996230c52 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/resources/application.properties @@ -0,0 +1,101 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +%prod.kafka.bootstrap.servers=localhost:9092 + +#start the workflow events +##application channels +mp.messaging.outgoing.start.connector=smallrye-kafka +mp.messaging.outgoing.start.topic=newAccountEventType +mp.messaging.outgoing.start.value.serializer=org.apache.kafka.common.serialization.StringSerializer +mp.messaging.outgoing.start.group.id=kogito-sw-callback + +##workflow channels +mp.messaging.incoming.newAccountEventType.connector=smallrye-kafka +mp.messaging.incoming.newAccountEventType.topic=newAccountEventType +mp.messaging.incoming.newAccountEventType.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer +mp.messaging.incoming.newAccountEventType.group.id=kogito-sw-callback +mp.messaging.incoming.newAccountEventType.auto.offset.reset=earliest + +#activate account events +##application channels +mp.messaging.outgoing.activated.connector=smallrye-kafka +mp.messaging.outgoing.activated.value.serializer=org.apache.kafka.common.serialization.StringSerializer +mp.messaging.outgoing.activated.topic=activatedAccount +mp.messaging.outgoing.activated.group.id=kogito-sw-callback + +mp.messaging.incoming.activate.connector=smallrye-kafka +mp.messaging.incoming.activate.topic=activateAccount +mp.messaging.incoming.activate.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer +mp.messaging.incoming.activate.group.id=kogito-sw-callback +mp.messaging.incoming.activate.auto.offset.reset=earliest + +##workflow channels +mp.messaging.incoming.activatedAccount.connector=smallrye-kafka +mp.messaging.incoming.activatedAccount.topic=activatedAccount +mp.messaging.incoming.activatedAccount.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer +mp.messaging.incoming.activatedAccount.group.id=kogito-sw-callback +mp.messaging.incoming.activatedAccount.auto.offset.reset=earliest + +mp.messaging.outgoing.activateAccount.connector=smallrye-kafka +mp.messaging.outgoing.activateAccount.value.serializer=org.apache.kafka.common.serialization.StringSerializer +mp.messaging.outgoing.activateAccount.topic=activateAccount +mp.messaging.outgoing.activateAccount.group.id=kogito-sw-callback + +#validate email events +##application channels +mp.messaging.incoming.validate.connector=smallrye-kafka +mp.messaging.incoming.validate.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer +mp.messaging.incoming.validate.topic=validateAccountEmail +mp.messaging.incoming.validate.group.id=kogito-sw-callback +mp.messaging.incoming.validate.auto.offset.reset=earliest + +mp.messaging.outgoing.validated.connector=smallrye-kafka +mp.messaging.outgoing.validated.topic=validatedAccountEmail +mp.messaging.outgoing.validated.value.serializer=org.apache.kafka.common.serialization.StringSerializer +mp.messaging.outgoing.validated.group.id=kogito-sw-callback + +##workflow channels +mp.messaging.outgoing.validateAccountEmail.connector=smallrye-kafka +mp.messaging.outgoing.validateAccountEmail.topic=validateAccountEmail +mp.messaging.outgoing.validateAccountEmail.value.serializer=org.apache.kafka.common.serialization.StringSerializer +mp.messaging.outgoing.validateAccountEmail.group.id=kogito-sw-callback + +mp.messaging.incoming.validatedAccountEmail.connector=smallrye-kafka +mp.messaging.incoming.validatedAccountEmail.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer +mp.messaging.incoming.validatedAccountEmail.topic=validatedAccountEmail +mp.messaging.incoming.validatedAccountEmail.group.id=kogito-sw-callback +mp.messaging.incoming.validatedAccountEmail.auto.offset.reset=earliest + +#Persistence configuration +kogito.persistence.type=mongodb + +quarkus.mongodb.database=kogito +%prod.quarkus.mongodb.database=kogito + +kogito.persistence.proto.marshaller=true + +quarkus.grpc.dev-mode.force-server-start=false + +# profile to pack this example into a container, to use it execute activate the maven container profile, -Dcontainer +%container.quarkus.container-image.build=true +%container.quarkus.container-image.push=false +%container.quarkus.container-image.group=${USER} +%container.quarkus.container-image.registry=dev.local +%container.quarkus.container-image.tag=1.0-SNAPSHOT diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/resources/correlation.sw.json b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/resources/correlation.sw.json new file mode 100644 index 0000000000..b6a44aeb13 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/main/resources/correlation.sw.json @@ -0,0 +1,104 @@ +{ + "id": "correlation", + "version": "1.0", + "name": "Workflow Correlation example", + "description": "An example of how to use correlation on events", + "start": "New User Account Request", + "events": [ + { + "name": "newAccountEvent", + "source": "", + "type": "newAccountEventType", + "correlation": [ + { + "contextAttributeName": "userid" + } + ] + }, + { + "name": "validateAccountEmailEvent", + "source": "workflow", + "type": "validateAccountEmail" + }, + { + "name": "validatedAccountEmailEvent", + "source": "workflow", + "type": "validatedAccountEmail", + "correlation": [ + { + "contextAttributeName": "userid" + } + ] + }, + { + "name": "activateAccountEvent", + "source": "workflow", + "type": "activateAccount" + }, + { + "name": "activatedAccountEvent", + "source": "workflow", + "type": "activatedAccount", + "correlation": [ + { + "contextAttributeName": "userid" + } + ] + } + ], + "functions": [ + { + "name": "complete", + "type": "custom", + "operation": "service:java:org.kie.kogito.examples.EventsService::complete" + } + ], + "states": [ + { + "name":"New User Account Request", + "type":"event", + "onEvents": [{ + "eventRefs": ["newAccountEvent"] + }], + "transition": "Validate User Email" + }, + { + "name": "Validate User Email", + "type": "callback", + "action": { + "name": "publish validate event", + "eventRef": { + "triggerEventRef": "validateAccountEmailEvent" + } + }, + "eventRef": "validatedAccountEmailEvent", + "transition": "Activate User Account" + }, +{ + "name": "Activate User Account", + "type": "callback", + "action": { + "name": "publish Activate Account event", + "eventRef": { + "triggerEventRef": "activateAccountEvent" + } + }, + "eventRef": "activatedAccountEvent", + "transition": "Account Creation Completed" + }, + + { + "name": "Account Creation Completed", + "type": "operation", + "actions": [ + { + "name": "accountCreationCompleted", + "functionRef": { + "refName": "complete" + } + } + ], + "end": true + } + ] +} diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/test/java/org/kie/kogito/examples/CorrelationIT.java b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/test/java/org/kie/kogito/examples/CorrelationIT.java new file mode 100644 index 0000000000..9f8a24fcba --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/test/java/org/kie/kogito/examples/CorrelationIT.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.kie.kogito.examples; + +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusIntegrationTest; +import io.restassured.http.ContentType; + +import static io.restassured.RestAssured.given; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.hamcrest.Matchers.notNullValue; + +@QuarkusIntegrationTest +class CorrelationIT { + + public static final String HEALTH_URL = "/q/health"; + public static final int TIMEOUT = 2; + + private String userId = "12345"; + + @Test + void testCorrelation() { + //health check - wait to be ready + await() + .atMost(TIMEOUT, MINUTES) + .pollDelay(2, SECONDS) + .pollInterval(1, SECONDS) + .untilAsserted(() -> given() + .contentType(ContentType.JSON) + .accept(ContentType.JSON) + .get(HEALTH_URL) + .then() + .statusCode(200)); + + //start workflow + given() + .contentType(ContentType.JSON) + .accept(ContentType.JSON) + .pathParam("userId", userId) + .post("/account/{userId}") + .then() + .statusCode(201); + + //check instance created + AtomicReference processInstanceId = new AtomicReference<>(); + await().atMost(TIMEOUT, MINUTES) + .pollInterval(1, SECONDS) + .untilAsserted(() -> processInstanceId.set(given() + .accept(ContentType.JSON) + .pathParam("userId", userId) + .get("/account/{userId}") + .then() + .statusCode(200) + .body("processInstanceId", notNullValue()) + .extract() + .body().path("processInstanceId"))); + + //check instance completed + await() + .atMost(TIMEOUT, MINUTES) + .pollInterval(1, SECONDS) + .untilAsserted(() -> given() + .contentType(ContentType.JSON) + .accept(ContentType.JSON) + .pathParam("processInstanceId", processInstanceId.get()) + .get("/correlation/{processInstanceId}") + .then() + .statusCode(404)); + } +} diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/test/resources/application.properties b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/test/resources/application.properties new file mode 100644 index 0000000000..50bf6c1154 --- /dev/null +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus-mongodb/src/test/resources/application.properties @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Quarkus +quarkus.http.test-port=0 + +# Temporary fix for test to pass due to issue in Quarkus classloading resolver +quarkus.class-loading.parent-first-artifacts=org.testcontainers:testcontainers \ No newline at end of file diff --git a/serverless-workflow-examples/serverless-workflow-correlation-quarkus/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-correlation-quarkus/src/main/resources/application.properties index 307953b261..7a9f24ce65 100644 --- a/serverless-workflow-examples/serverless-workflow-correlation-quarkus/src/main/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-correlation-quarkus/src/main/resources/application.properties @@ -87,7 +87,7 @@ mp.messaging.incoming.validatedAccountEmail.auto.offset.reset=earliest kogito.persistence.type=jdbc #run create tables scripts -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true quarkus.datasource.db-kind=postgresql %prod.quarkus.datasource.username=postgres diff --git a/serverless-workflow-examples/serverless-workflow-custom-type/serverless-workflow-custom-rpc/src/main/java/org/kie/kogito/examples/sw/custom/RPCCustomWorkItemHandler.java b/serverless-workflow-examples/serverless-workflow-custom-type/serverless-workflow-custom-rpc/src/main/java/org/kie/kogito/examples/sw/custom/RPCCustomWorkItemHandler.java index 64beded70a..87dc724411 100644 --- a/serverless-workflow-examples/serverless-workflow-custom-type/serverless-workflow-custom-rpc/src/main/java/org/kie/kogito/examples/sw/custom/RPCCustomWorkItemHandler.java +++ b/serverless-workflow-examples/serverless-workflow-custom-type/serverless-workflow-custom-rpc/src/main/java/org/kie/kogito/examples/sw/custom/RPCCustomWorkItemHandler.java @@ -26,10 +26,9 @@ import jakarta.enterprise.context.ApplicationScoped; import org.kie.kogito.examples.sw.custom.CalculatorClient.OperationId; -import org.kie.kogito.internal.process.runtime.KogitoWorkItem; +import org.kie.kogito.internal.process.workitem.KogitoWorkItem; import org.kie.kogito.serverless.workflow.WorkflowWorkItemHandler; - @ApplicationScoped public class RPCCustomWorkItemHandler extends WorkflowWorkItemHandler { @@ -37,23 +36,23 @@ public class RPCCustomWorkItemHandler extends WorkflowWorkItemHandler { public static final String HOST = "host"; public static final String PORT = "port"; public static final String OPERATION = "operation"; - + @Override - protected Object internalExecute(KogitoWorkItem workItem, Map parameters) { + protected Object internalExecute(KogitoWorkItem workItem, Map parameters) { try { Iterator iter = parameters.values().iterator(); Map metadata = workItem.getNodeInstance().getNode().getMetaData(); String operationId = (String) metadata.get(OPERATION); if (operationId == null) { - throw new IllegalArgumentException ("Operation is a mandatory parameter"); + throw new IllegalArgumentException("Operation is a mandatory parameter"); } - return CalculatorClient.invokeOperation((String)metadata.getOrDefault(HOST,"localhost"), (int) metadata.getOrDefault(PORT, 8082), - OperationId.valueOf(operationId.toUpperCase()), (Integer)iter.next(), (Integer)iter.next()); - } catch (IOException io ) { + return CalculatorClient.invokeOperation((String) metadata.getOrDefault(HOST, "localhost"), (int) metadata.getOrDefault(PORT, 8082), + OperationId.valueOf(operationId.toUpperCase()), (Integer) iter.next(), (Integer) iter.next()); + } catch (IOException io) { throw new UncheckedIOException(io); } } - + @Override public String getName() { return NAME; diff --git a/serverless-workflow-examples/serverless-workflow-data-index-persistence-addon-quarkus/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-data-index-persistence-addon-quarkus/src/main/resources/application.properties index 0542e7832c..74efbe9153 100644 --- a/serverless-workflow-examples/serverless-workflow-data-index-persistence-addon-quarkus/src/main/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-data-index-persistence-addon-quarkus/src/main/resources/application.properties @@ -10,9 +10,7 @@ quarkus.datasource.db-kind=postgresql %container.quarkus.datasource.password=postgres %container.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/kogito -quarkus.flyway.migrate-at-start=true -quarkus.flyway.baseline-on-migrate=true -quarkus.hibernate-orm.database.generation=update +kie.flyway.enabled=true kogito.service.url=http://localhost:8080 diff --git a/serverless-workflow-examples/serverless-workflow-data-index-quarkus/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-data-index-quarkus/src/main/resources/application.properties index 5a65acb07b..bdb9623e63 100644 --- a/serverless-workflow-examples/serverless-workflow-data-index-quarkus/src/main/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-data-index-quarkus/src/main/resources/application.properties @@ -46,8 +46,9 @@ quarkus.http.test-port=0 kogito.persistence.type=jdbc kogito.persistence.proto.marshaller=false quarkus.datasource.db-kind=postgresql + #run create tables scripts -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true quarkus.kubernetes-client.devservices.enabled=false quarkus.native.native-image-xmx=8g diff --git a/serverless-workflow-examples/serverless-workflow-data-index-quarkus/src/test/resources/application.properties b/serverless-workflow-examples/serverless-workflow-data-index-quarkus/src/test/resources/application.properties index e0723a1fac..5d92be7766 100644 --- a/serverless-workflow-examples/serverless-workflow-data-index-quarkus/src/test/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-data-index-quarkus/src/test/resources/application.properties @@ -18,4 +18,3 @@ # quarkus.kogito.devservices.enabled=true -quarkus.flyway.table=test_flyway \ No newline at end of file diff --git a/serverless-workflow-examples/serverless-workflow-dmn-quarkus/pom.xml b/serverless-workflow-examples/serverless-workflow-dmn-quarkus/pom.xml index 626db11bf3..467b3ac1e6 100644 --- a/serverless-workflow-examples/serverless-workflow-dmn-quarkus/pom.xml +++ b/serverless-workflow-examples/serverless-workflow-dmn-quarkus/pom.xml @@ -37,10 +37,10 @@ Kogito Example :: Serverless Workflow :: DMN:: Quarkus Kogito Serverless Workflow DMN Example - Quarkus - 3.2.10.Final + 3.8.4 quarkus-bom io.quarkus - 3.2.10.Final + 3.8.4 org.kie.kogito kogito-bom 999-SNAPSHOT diff --git a/serverless-workflow-examples/serverless-workflow-loanbroker-showcase/loanbroker-flow/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-loanbroker-showcase/loanbroker-flow/src/main/resources/application.properties index 6f28b4ce8a..5119511406 100644 --- a/serverless-workflow-examples/serverless-workflow-loanbroker-showcase/loanbroker-flow/src/main/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-loanbroker-showcase/loanbroker-flow/src/main/resources/application.properties @@ -56,7 +56,7 @@ quarkus.knative.max-scale=1 %persistence.quarkus.container-image.build=true %persistence.quarkus.datasource.db-kind=postgresql -%persistence.quarkus.flyway.migrate-at-start=true +%persistence.kie.flyway.enabled=true %persistence.kogito.persistence.type=jdbc %persistence.kogito.persistence.proto.marshaller=false %persistence.kogito.persistence.query.timeout.millis=10000 diff --git a/serverless-workflow-examples/serverless-workflow-newsletter-subscription/subscription-flow/src/main/resources/application-knative.properties b/serverless-workflow-examples/serverless-workflow-newsletter-subscription/subscription-flow/src/main/resources/application-knative.properties index 8ce2a74312..ebe362b111 100644 --- a/serverless-workflow-examples/serverless-workflow-newsletter-subscription/subscription-flow/src/main/resources/application-knative.properties +++ b/serverless-workflow-examples/serverless-workflow-newsletter-subscription/subscription-flow/src/main/resources/application-knative.properties @@ -24,7 +24,7 @@ kogito.service.url=${knative:services.v1.serving.knative.dev/newsletter-showcase # When the application is generated with the knative profile, it'll require a PostgreSQL database. # Kogito persistence configurations for enabling the serverless workflow persistence quarkus.datasource.db-kind=postgresql -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true kogito.persistence.type=jdbc kogito.persistence.proto.marshaller=false kogito.persistence.query.timeout.millis=10000 diff --git a/serverless-workflow-examples/serverless-workflow-qas-service-showcase/query-answer-service/src/main/resources/application-knative.properties b/serverless-workflow-examples/serverless-workflow-qas-service-showcase/query-answer-service/src/main/resources/application-knative.properties index 8ffd4e9069..22a58bf066 100644 --- a/serverless-workflow-examples/serverless-workflow-qas-service-showcase/query-answer-service/src/main/resources/application-knative.properties +++ b/serverless-workflow-examples/serverless-workflow-qas-service-showcase/query-answer-service/src/main/resources/application-knative.properties @@ -24,7 +24,7 @@ quarkus.log.category."org.kie".level=DEBUG quarkus.datasource.db-kind=postgresql kogito.persistence.type=jdbc kogito.persistence.proto.marshaller=false -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true kogito.persistence.query.timeout.millis=10000 # DB configuration, also used by the PostgreSqlQueryRecordRepository diff --git a/serverless-workflow-examples/serverless-workflow-qas-service-showcase/query-answer-service/src/main/resources/application-persistence.properties b/serverless-workflow-examples/serverless-workflow-qas-service-showcase/query-answer-service/src/main/resources/application-persistence.properties index 54f49a9f6e..44accd2593 100644 --- a/serverless-workflow-examples/serverless-workflow-qas-service-showcase/query-answer-service/src/main/resources/application-persistence.properties +++ b/serverless-workflow-examples/serverless-workflow-qas-service-showcase/query-answer-service/src/main/resources/application-persistence.properties @@ -28,7 +28,7 @@ quarkus.datasource.db-kind=postgresql kogito.persistence.type=jdbc kogito.persistence.proto.marshaller=false kogito.persistence.query.timeout.millis=10000 -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true # DB configuration, also used by the PostgreSqlQueryRecordRepository %prod.quarkus.datasource.reactive.url=postgresql://localhost:5432/postgres diff --git a/serverless-workflow-examples/serverless-workflow-timeouts-showcase-embedded/pom.xml b/serverless-workflow-examples/serverless-workflow-timeouts-showcase-embedded/pom.xml index 30437ca1c5..3948698300 100644 --- a/serverless-workflow-examples/serverless-workflow-timeouts-showcase-embedded/pom.xml +++ b/serverless-workflow-examples/serverless-workflow-timeouts-showcase-embedded/pom.xml @@ -51,7 +51,7 @@ 5.1.3 3.6.0 - 0.2.2 + 0.2.3 diff --git a/serverless-workflow-examples/serverless-workflow-timeouts-showcase-embedded/src/main/resources/application.properties b/serverless-workflow-examples/serverless-workflow-timeouts-showcase-embedded/src/main/resources/application.properties index 370f3de745..98ef9ccbbf 100644 --- a/serverless-workflow-examples/serverless-workflow-timeouts-showcase-embedded/src/main/resources/application.properties +++ b/serverless-workflow-examples/serverless-workflow-timeouts-showcase-embedded/src/main/resources/application.properties @@ -32,7 +32,7 @@ kogito.persistence.type=jdbc kogito.persistence.proto.marshaller=false kogito.persistence.query.timeout.millis=10000 quarkus.datasource.db-kind=postgresql -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true # Configuration for the incoming cloud events received by the serverless workflows. mp.messaging.incoming.kogito_incoming_stream.connector=quarkus-http diff --git a/serverless-workflow-examples/serverless-workflow-timeouts-showcase-extended/src/main/resources/application-knative.properties b/serverless-workflow-examples/serverless-workflow-timeouts-showcase-extended/src/main/resources/application-knative.properties index 72672f738c..64090f51e7 100644 --- a/serverless-workflow-examples/serverless-workflow-timeouts-showcase-extended/src/main/resources/application-knative.properties +++ b/serverless-workflow-examples/serverless-workflow-timeouts-showcase-extended/src/main/resources/application-knative.properties @@ -22,7 +22,7 @@ kogito.persistence.type=jdbc kogito.persistence.proto.marshaller=false kogito.persistence.query.timeout.millis=10000 quarkus.datasource.db-kind=postgresql -quarkus.flyway.migrate-at-start=true +kie.flyway.enabled=true # This env var will be generated with the quarkus-kubernetes plugin. See below. quarkus.datasource.jdbc.url=jdbc:postgresql://${POSTGRES_HOST:localhost}:5432/postgres