You can create a Business Service using the Workflow engines with the Quarkus framework support.

During the compilation, some code is automatically generated by a specific Maven plugin where part of the code is common and the rest of it is engine-specific.

For each model, REST endpoints are generated, that are specific to the model and the engine.

You can add custom classes to the Business Service project to provide additional functionality, which is built with the automatically generated code as in normal Java applications.

If you are migrating from version 8.0.x, you can refer to the available migration tutorials. For more information, see BAMOE v8 to v9 migration tutorials.

Dependencies

Use the Quarkus BOM to facilitate management of all BAMOE libraries.

Add the com.ibm.bamoe:bamoe-quarkus-bom dependency to the <dependencyManagement> section of your project POM. You can then add the dependencies you require from those available in the BOM POMs using the <dependency> tags. For more information, see BAMOE Bill of Materials (BOM).

To correctly build a workflow Business Service project with Quarkus and package the application, use org.jbpm:jbpm-with-drools-quarkus dependency and the io.quarkus:quarkus-maven-plugin Maven plugin. For more information, see org.jbpm:jbpm-with-drools-quarkus and io.quarkus:quarkus-maven-plugin external documentation.

For the org.jbpm:jbpm-with-drools-quarkus dependency, see Workflows (Quarkus).

Workflow subsystem add-ons (Quarkus)

The following Quarkus add-ons provide extensions for enabling persistence, embedded subsystem execution, and integration with workflow-related components such as Data Index, Data Audit, Jobs Service, and User Tasks.

Data-Index add-on

Use to enable the workflow runtime to persist data directly into the Data-Index subsystem. For more information, see Workflows (Stateful) subsystem → Data-Index.

  • org.kie:kogito-addons-quarkus-data-index-jpa

The following add-ons require JDBC driver configuration when persistence layers are involved. For more information, see Enabling persistence for stateful Workflows.

Data-Audit add-ons

Use to enable Data-Audit integration with the Business Service. For more information, see Workflows (Stateful) subsystem → Data-Audit.

  • org.kie:kogito-addons-quarkus-data-audit

  • org.kie:kogito-addons-quarkus-data-audit-jpa

Embedded Jobs Service add-ons

Use to enable the colocation of the Jobs Service within the workflow runtime. For more information, see Workflows (Stateful) subsystem → Jobs Service.

  • org.kie:kogito-addons-quarkus-embedded-jobs

  • org.kie:kogito-addons-quarkus-embedded-jobs-jpa

User Tasks add-on

Use database-backed storage to enable the User Tasks subsystem to persist its data instead of relying on the default in‑memory storage. For more information, see Workflows (Stateful) subsystem → User Tasks.

  • org.jbpm:jbpm-addons-quarkus-usertask-storage-jpa

With a stateful Workflow you will often combine events and messages in your Workflows, see Using Events in Workflows for more details on implementing Events and Messaging within Workflows.

Depending on your Business Services with workflow(s) use case many Add-ons are available to be configured as required, see Reference → BAMOE Maven repository libraries for a complete list.

See the complete POM for workflows for a Business Service with stateful workflow on Quarkus.

Beside the POM file, the application.properties file is required to further customize the application with Quarkus or BAMOE specific properties (for example, server.address).

Enabling persistence for stateful Workflows

BAMOE Business Services containing workflow(s) and all the Workflow subsystems (Data-Index, Data-Audit, Jobs Service, and User Tasks) use JDBC to persist in relational databases.

All BAMOE components rely on the default DataSource to establish the connection with the Database. You must correctly configure a DataSource in your application by following the Quarkus platform guidelines.

Configuring persistence for BAMOE requires the following set of dependencies and configurations to be added to your application:

io.quarkus:quarkus-agroal

For Quarkus DataSource Connection Pool with Security and Transaction support.

io.quarkus:quarkus-jdbc-{{your-database-type}}

For Database Specific Quarkus JDBC Driver.

org.kie:kie-addons-quarkus-persistence-jdbc

For KIE JDBC Persistence Add-on for Quarkus that enables persistence for the Workflow Engine with JDBC. For the dependency, see Workflows Stateful persistence.

Note
For more information about how to configure DataSources in Quarkus, see Configure data sources in Quarkus guide.

Configuring persistence for PostgreSQL

To configure PostgreSQL persistence for your Business Service, you need the io.quarkus:quarkus-jdbc-postgresql dependency.

Add the following configuration properties required in your application.properties:

<!-- Application default Datasource - PostgreSQL -->
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=bamoe-user
quarkus.datasource.password=bamoe-pass
quarkus.datasource.jdbc.url=${QUARKUS_DATASOURCE_JDBC_URL:jdbc:postgresql://0.0.0.0:5432/bamoe-db}

<!-- Enabling jdbc persistence -->
kogito.persistence.type=jdbc

Configuring persistence for Microsoft SQL Server

To configure Microsoft SQL Server persistence for your Business Service, you need the io.quarkus:quarkus-jdbc-mssql dependency.

Add the following configuration properties required in your application.properties:

<!-- Application default Datasource - Microsoft SQL Server -->
quarkus.datasource.db-kind=mssql
quarkus.datasource.username=bamoe-user
quarkus.datasource.password=bamoe-pass
quarkus.datasource.jdbc.url=${QUARKUS_DATASOURCE_JDBC_URL:jdbc:sqlserver://0.0.0.0:1433;DatabaseName=bamoe-db;encrypt=true;trustServerCertificate=true;}

<!-- Enabling jdbc persistence -->
kogito.persistence.type=jdbc
Note
If your Business Service uses Microsoft SQL Server persistence in Quarkus Dev Mode and you want to use the Database Dev Services, read the Dev Services for Databases guide and apply the required License Acceptance configuration as explained in the Proprietary Databases - License Acceptance topic.

BAMOE mappings for Microsoft SQL Server

Additionally, if the Business Service includes Data-Index or Jobs Service, you need to add the com.ibm.bamoe:bamoe-mssql-mappings dependency to ensure the correct behavior of those components.

This module includes the necessary Hibernate ORM mappings to support remapping of some JPA entities used in both components. The mappings contained are:

META-INF/bamoe-data-index-orm.xml

This file remaps some entities from the data-index component.

META-INF/bamoe-job-service-orm.xml

This file remaps some entities from the job-service component.

com.ibm.bamoe:bamoe-mssql-mappings

Required database-specific mappings to ensure the persistence layer works correctly with the database dialect and limitations.

Those mappings can be configured by using the quarkus.hibernate-orm.mapping-files configuration, and each one should be added only if the associated component is present in the application dependencies.

To correctly configure the Hibernate mappings, in your application POM add com.ibm.bamoe:bamoe-mssql-mappings dependency. For the dependency, see Workflows Stateful persistence.

Add the following configuration property required in your application.properties:

quarkus.hibernate-orm.mapping-files=META-INF/bamoe-data-index-orm.xml,META-INF/bamoe-job-service-orm.xml

Transaction isolation settings for Microsoft SQL Server

To ensure BAMOE works properly when configured with a Microsoft SQL Server database and to prevent deadlocks under load, you must enable snapshot isolation at both the database and application levels.

At the database level, enable snapshot isolation and row versioning by running the following SQL commands:

    ALTER DATABASE <DATABASE_NAME> SET ALLOW_SNAPSHOT_ISOLATION ON;
    ALTER DATABASE <DATABASE_NAME> SET READ_COMMITTED_SNAPSHOT ON;

At the application level, configure the transaction isolation level at the connection level by adding the following property:

quarkus.datasource.jdbc.new-connection-sql=SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
Note
This property requires the database schema to be set up manually with the configuration property kie.flyway.enabled set to false.

Configuring persistence for Oracle

To configure Oracle persistence for your Business Service, you need to add the io.quarkus:quarkus-jdbc-oracle dependency.

Add the following configuration properties required in your application.properties:

<!-- Application default Datasource - Oracle -->
quarkus.datasource.db-kind=oracle
quarkus.datasource.username=bamoe-user
quarkus.datasource.password=bamoe-pass
quarkus.datasource.jdbc.url=jdbc:oracle:thin:@//oracle:1521/FREEPDB1

<!-- Enabling jdbc persistence -->
kogito.persistence.type=jdbc

BAMOE mappings for Oracle

Additionally, if the Business Service includes User Tasks or Jobs Service, you need to add the com.ibm.bamoe:bamoe-oracle-mappings dependency, which includes the Hibernate ORM mappings that remap some of the JPA entities used in both components and ensure the correct behavior. The mappings contained are:

META-INF/bamoe-user-task-orm.xml

This file remaps some entities from the jbpm-usertask-storage-jpa component.

META-INF/bamoe-job-service-orm.xml

This file remaps some entities from the job-service component.

com.ibm.bamoe:bamoe-oracle-mappings

Required database-specific mappings to ensure persistence layer works correctly with that database’s dialect and limitations.

Those mappings can be configured by using the quarkus.hibernate-orm.mapping-files configuration, and each one should be added only if the associated component is present in the application dependencies.

To correctly configure the Hibernate mappings, in your application POM add com.ibm.bamoe:bamoe-oracle-mappings dependency. For the dependency, see Workflows Stateful persistence.

Add the following configuration property required in your application.properties:

quarkus.hibernate-orm.mapping-files=META-INF/bamoe-user-task-orm.xml,META-INF/bamoe-job-service-orm.xml

Configuring persistence for Db2

To configure Db2 persistence for your Business Service, you need to add the io.quarkus:quarkus-jdbc-db2 dependency.

Add the following configuration properties required in your application.properties:

<!-- Application default Datasource - Db2 -->
quarkus.datasource.db-kind=db2
quarkus.datasource.username=bamoe-user
quarkus.datasource.password=bamoe-pass
quarkus.datasource.jdbc.url=jdbc:db2://host:port/testdb

<!-- Enabling jdbc persistence -->
kogito.persistence.type=jdbc

Configuring persistence for H2 (Development only)

In development environments, you can use H2 persistence for your Business Service. You need to add the io.quarkus:quarkus-jdbc-h2 dependency.

Add the following configuration property required in your application.properties:

<!-- Application default Datasource - H2 -->
quarkus.datasource.db-kind=h2
datasource.devservices.properties.NON_KEYWORDS=VALUE,KEY

<!-- Enabling jdbc persistence -->
kogito.persistence.type=jdbc

Setting up the database for stateful Workflows in development

All stateful Workflows subsystems brought by BAMOE into your Business Service project come with KIE Flyway migrations, a sandboxed Flyway-based mechanism that automatically creates the database schema for you during startup. This is convenient in Dev environments but is not suitable for production database instances.

To enable this feature, add the following kie.flyway.enabled property in your application.properties project file, which is found in src/main/resources:

kie.flyway.enabled=false # for production
%dev.kie.flyway.enabled=true

Your development database schema will be automatically created for you.

Code structure

A Workflow service built with Quarkus includes the following key elements that define its structure, behavior, and runtime configuration:

Java domain models and business services

Located under src/main/java, these classes implement the domain model and any optional business services. Domain model classes define the structure of process data (e.g. CandidateData, Offer, or CreditCardDetails) that workflows use as process variables. Business services may be invoked from Service Tasks within workflows.

Workflow definitions

One or more BPMN process models (.bpmn or .bpmn2) are placed under src/main/resources. These files describe the workflow logic, tasks, transitions, and overall process flow executed by the service.

Application and additional configuration

The src/main/resources directory also contains the application.properties file, which configures Quarkus and BAMOE features such as persistence, the embedded Job Service, and Data Index. Additional configuration files, such as calendars or custom properties, may also be included.

Testing resources

Under src/test/java, JUnit test classes validate the correct execution of workflows.

Testing Workflow execution

Workflow services can be tested manually or with automated JUnit tests.

Manual testing instructions:

  1. Start the application (see Running in README).

  2. Trigger a workflow instance via REST (for example, using curl or Swagger UI)

    curl -H "Content-Type: application/json" -H "Accept: application/json" \
      -X POST http://localhost:8080/hiring \
      -d '{"candidateData": { "name": "Jon", "lastName": "Snow", "email": "jon@snow.org", "experience": 5, "skills": ["Java", "Kogito", "Fencing"]}}'
  3. Complete user tasks by querying and posting to the appropriate endpoints, as described in the README.

Automated testing with JUnit:

Workflow services can also be tested using JUnit and the @QuarkusTest annotation. This allows validation of process execution, business logic, and features.

@QuarkusTest
public class CreditCardProcessIT {

    private static final String PROCESS_ID = "BusinessCalendarCreditBill";
    private static final String CARD_NUMBER = "434354343";

    @jakarta.inject.Inject
    ProcessConfig processConfig;

    @Test
    public void testCardPaymentInWorkingDay() throws Exception {
        String id = given()
                .contentType(ContentType.JSON)
                .body("{}")
                .when()
                .post("/" + PROCESS_ID)
                .then()
                .statusCode(201)
                .body("id", notNullValue())
                .body("creditCardDetails.cardNumber", is(CARD_NUMBER))
                .body("creditCardDetails.status", is("Bill Due"))
                .extract()
                .path("id");

        Thread.sleep(2000);
        BusinessCalendar businessCalendar = processConfig.getBusinessCalendar();
        assertThat(businessCalendar).isNotNull();
        long timeDuration = businessCalendar.calculateBusinessTimeAsDuration("15s");
        if (timeDuration > 1000L) {
            given()
                    .when()
                    .get("/" + PROCESS_ID + "/" + id)
                    .then()
                    .statusCode(200)
                    .body("id", is(id))
                    .body("creditCardDetails.cardNumber", is(CARD_NUMBER))
                    .body("creditCardDetails.status", is("Bill Due"));
        } else {
            given()
                    .when()
                    .get("/" + PROCESS_ID)
                    .then()
                    .statusCode(200)
                    .body(equalTo("[]"));
        }
    }
}

Testing with the BAMOE Quarkus Dev UI extension

The BAMOE Quarkus Dev UI extension is a web app that attaches to the Quarkus Dev UI and allows developers to interact and manage running processes locally.

BAMOE Quarkus Dev UI extension Process Instances page

After you create a Business Service with the Quarkus framework support, add the com.ibm.bamoe:bamoe-quarkus-devui BAMOE Quarkus Dev UI extension dependency to your POM file. For the dependency, see Workflows (Quarkus dev + testing).

Update the application.properties file to add users and user groups in the following format:

bamoe.devui.users.<username>.groups=<comma separated list of groups>

For example:

bamoe.devui.users.jdoe.groups=admin,HR,IT
bamoe.devui.users.alice.groups=HR,IT
bamoe.devui.users.admin.groups=admin

To include the Swagger UI with the Open API specifications for your Workflow, add the following properties:

quarkus.swagger-ui.always-include=true
quarkus.smallrye-openapi.path=docs/openapi.json

To install the dependencies and run your Quarkus application in Dev mode locally, open a new terminal and execute one of the following commands:

mvn clean quarkus:dev

gradle clean quarkusDev

Note
Maven places all build artifacts in the /target directory, while Gradle places them in the build/ directory.

To access the BAMOE Quarkus Dev UI extension, open a browser and navigate to http://localhost:8080/q/dev-ui/. This is the Quarkus Dev UI, where the BAMOE Quarkus Dev UI extension is listed.

Accessing the BAMOE Quarkus Dev UI extension from the Quarkus Dev UI

Scroll down to the BAMOE Quarkus Dev UI box and click on any item in the list (Process Instances, Tasks, Jobs, or Forms) to open the BAMOE Quarkus Dev UI extension web app.

Process Instances

Process Instances page

The Process Instances page displays all the running processes and their execution status. Click on any process instance to open the Process Instance details page.

Process Details page
Starting a new process instance

To start a new process instance, go to the Process Definitions tab. You will see a list of all the Process Definitions, one for each Workflow in your resources directory.

Process Definitions page

Click on any Process Definition to open its respective initialization form.

Process Definition form page

Fill in the form with relevant data for your Workflow and click on Start.

Note
The Process Definitions forms are auto generated, but can be customized in the Forms page. See more in the Forms section.

Jobs

Jobs page

The Jobs page displays all the scheduled jobs and their execution status. Click on the actions menu on any job to show available options, including Details, which opens the job details modal.

Job details page

Tasks

Tasks page

The Tasks page displays all the User Tasks and their priorities and status. Click on the task name to open the User Task Form that can be filled and submitted to progress it to the next phase.

Task Form page

Click on View Details to open a side panel with more details regarding the current task, including the parent process, possible assigned users/groups, id, name, and state.

Task details panel
Note
The Task forms are auto generated, but can be customized in the Forms page. See more in the Forms section.

Forms

Forms page

The Forms page displays all the available forms in the project. It is initially empty, since all forms (for User Tasks and Process Definitions) are auto generated.

To add custom forms (for the hiring Process Definition or HR Interview User Task for example), follow the steps in Form code generation functionality and then place the generated forms in the src/main/resources/custom-forms-dev folder.

Process Instance Migration

If you have added the BAMOE Process Instance Migration (PIM) Add-on dependency to your Business Service you can access the same PIM User Interface that is integrated in the BAMOE Management Console, to be able to manage the migration of in-flight Process Instances to updated Process Definitions, see Managing live Workflows using BAMOE Management Console

Using the Swagger UI

Although the Swagger UI is not directly related to the BAMOE Quarkus Dev UI extension, it is a useful tool to explore the REST and GraphQL API endpoints of your Workflow.

Swagger UI page

The Swagger UI lists all endpoints generated for your Workflow as well as the extra endpoints for management, such as /management/processes.

To use the API, select any endpoint and click on Try it out to test it.

Swagger UI try it out page

Using the Data-Index Graphql UI

Data-Index provides a GraphiQL UI that provides a graphic interface to run and test GraphQL queries against the Data-Index GraphQL API in your Business Service.

Data-Index GraphiQL UI

To enable the GraphiQL UI, add the following property in your application.properties file:

quarkus.kogito.data-index.graphql.ui.always-include=true

When enabled, to access the GraphiQL UI, in your browser navigate to http://localhost:8080/q/graphql-ui.

Note
GraphQL UI is enabled by default when running in Quarkus Development mode.

Hot-reload in dev mode

For medium to large sized Workflow services, recompiling and restarting the application upon code changes could be cumbersome and time-consuming. To simplify development, Quarkus offers an embedded hot-reload feature.

To trigger it, there are two steps:

  1. Modify any source file (such as a BPMN definition, Java class, or configuration file).

  2. Reload any page of the running application to see the changes applied immediately.

This allows you to iteratively develop workflows without restarting the application.

Debugging

Debugging a Workflow service in Quarkus follows the standard Java remote debugging setup:

  1. Create a remote debug configuration in your IDE on port 5005 (steps vary by IDE).

  2. Start the application in dev mode by using one of the following commands:

    mvn clean compile quarkus:dev
    ./gradlew clean build quarkusDev
  3. Put a breakpoint in one of the generated or custom classes.

  4. Connect your IDE debugger to port 5005.

It is also possible to block the compilation until a debugger is connected by using one of the following commands:

mvn clean compile quarkus:dev -Dsuspend
./gradlew clean build quarkusDev -Dsuspend