This example demonstrates the impact of a business calendar on process execution within a Springboot application. It showcases a business process involving credit card bill processing, which adapts to a business calendar defined in calendar.properties. This configuration modifies timer behaviors to respect working hours, holidays, and other schedule-based constraints.
BPMN2-BusinessCalendarBankTransaction.bpmn2: Defines the workflow for processing credit card transactions. Includes tasks such as processing the credit bill, verifying payment, handling timers, cancelling and bill settlement.
CreditCardService.java: Implements the logic for handling credit card payment processes.
calendar.properties: Configures business hours, holidays, and other calendar properties that affect scheduling and timer behavior.
The BPMN model (BPMN2-BusinessCalendarBankTransaction.bpmn2
) defines a workflow that includes the following main elements:
The initial trigger that starts the credit card bill processing workflow.
Process Credit Bill Properties (Top)
Process Credit Card Bill Assignments
A user task where the credit card details are validated, ensuring the payment is processed under valid terms.
Attached to a user task to simulate waiting for manual confirmation or user action. This timer can be configured to react differently based on the presence of the business calendar.
Executed if the timer expires without human action, leading to the cancellation of the payment process.
Cancel Payment (Top)
Cancel Payment Assignments
The final step where the payment is settled successfully on manual verification.
You will need:
mvn clean compile spring-boot:run
mvn clean package
To run the generated native executable, generated in target/
, execute
java -jar target/process-business-rules-springboot.jar
You can take a look at the OpenAPI definition - automatically generated and included in this service - to determine all available operations exposed by this service. For easy readability you can visualize the OpenAPI definition file using a UI tool like for example available Swagger UI.
In addition, various clients to interact with this service can be easily generated using this OpenAPI definition.
Once the service is up and running we can invoke the REST endpoints and examine the logic.
curl -X POST http://localhost:8080/BusinessCalendarCreditBill \ -H "Content-Type: application/json" \ -d '{"creditCardNumber": null, "creditCardDetails": {"cardNumber": "434353433", "status": "Bill Due"}}'
curl -X GET http://localhost:8080/BusinessCalendarCreditBill \ -H "Content-Type: application/json" \ -H "Accept: application/json"
curl -X GET http://localhost:8080/BusinessCalendarCreditBill/{id} \ -H "Content-Type: application/json" \ -H "Accept: application/json"
Default Behavior: If you do not input custom values in a calendar.properties file, the system will use the following default settings:
business.start.hour defaults to 9, and business.end.hour defaults to 17 (i.e.,9 AM to 5 PM workday).
business.weekend.days defaults to Saturday and Sunday (Sunday-1, Monday-2, Tuesday-3, Wednesday-4, Thursday-5, Friday-6, Saturday-7).
business.holiday.date.format defaults to yyyy-MM-dd, (input must match format defined format).
business.holidays by default will be considered empty, meaning no predefined holidays unless specified, if specified, it should be in the format defined by business.holiday.date.format, Holidays can be specified as individual dates (e.g., 2024-12-25,2024-12-31) or as a range of dates (e.g., 2024-11-12:2024-11-14).
business.cal.timezone defaults to the system’s default timezone, if configured, valid time-zone as per Valid timezone as per https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html should be specified.
Calculated Properties (Do not include in calendar.properties
file):
business.days.per.week: calculated value, 7 - business.weekend.days.
business.hours.per.day : Calculated value, business.end.hour - business.start.hour.
Behavior:
calendar.properties
To override default values, configure calendar.properties file based on requirements. In order to ensure more aligned functionality, please follow the rules outlined below. Adhering to these guidelines will help ensure that tasks are executed as expected. Incorrect configurations may result in unintended behavior, so it's recommended to input accurate values.
Property | Valid Range | Description |
---|---|---|
business.start.hour | 0-23 | Start hour of the workday |
business.end.hour | 0-23 | End hour of the workday |
business.weekend.days | 0-7 | Days considered as weekends (e.g., 1 = Sunday, 7 = Saturday). In case you want to consider all the days as working days i.e., no weekend days, input 0 as value considering working days as 7. |
business.holiday.date.format | (yyyy-MM-dd) | List of holidays |
business.holidays | Dates aligned with business.holiday.date.format | Date format for holidays |
business.cal.timezone | Valid timezone as per Java TimeZone Documentation | Timezone for calculations |
business.end.hour=23 business.start.hour=0 business.holiday.date.format=yyyy-MM-dd business.holidays=2024-10-30 business.weekend.days=6,7 business.cal.timezone=America/Toronto
Behavior:
Note: The test was performed at 16:13 on Monday, which falls under default working hours
The timer for the Verify Payment task will follow a straightforward countdown based on real time. If the specified time elapses i.e., 1 second, it immediately moves to cancel payment task.
POST/ BusinessCalendarCreditBill
curl -X POST http://localhost:8080/BusinessCalendarCreditBill \ -H "Content-Type: application/json" \ -d '{"creditCardNumber": null, "creditCardDetails": {"cardNumber": "434353433", "status": "Bill Due"}}'
curl -X GET http://localhost:8080/BusinessCalendarCreditBill \ -H "Content-Type: application/json" \ -H "Accept: application/json"
Note: The test was performed at 08:27 on Monday, which does not fall in the default working hours range
During non-working hours, the timer for the Verify Payment task will not trigger and the process remains in active state, does not move to cancel payment task.
POST/ BusinessCalendarCreditBill
curl -X POST http://localhost:8080/BusinessCalendarCreditBill \ -H "Content-Type: application/json" \ -d '{"creditCardNumber": null, "creditCardDetails": {"cardNumber": "434353433", "status": "Bill Due"}}'
curl -X GET http://localhost:8080/BusinessCalendarCreditBill \ -H "Content-Type: application/json" \ -H "Accept: application/json"
Note: The test was performed considering 24-hour workday properties with configured holiday i.e., business.holidays=2024-11-07
After calendar.properties file is added, build the example again “mvn clean compile quarkus:dev” or type ‘s’ in the quarkus terminal and hit enter just to restart.
POST/ BusinessCalendarCreditBill
curl -X POST http://localhost:8080/BusinessCalendarCreditBill \ -H "Content-Type: application/json" \ -d '{"creditCardNumber": null, "creditCardDetails": {"cardNumber": "434353433", "status": "Bill Due"}}'
curl -X GET http://localhost:8080/BusinessCalendarCreditBill \ -H "Content-Type: application/json" \ -H "Accept: application/json"
The node ‘Start’ for the process ‘BusinessCalendarCreditBill’, identified by 08ea5258-9d91-4f05-a8d8-184107c042ed, was triggered at 08:54:28,621.
At 08:54:28,629, the ‘Process Credit Bill’ node was activated.
At 08:54:28,653, verification step through the ‘Verify Payment’ node was started.
Subsequently, a human task was registered at 08:54:28,773.
The workflow transitioned to an ‘Active’ state at 08:54:28,808.
Due to mentioned “business.holidays property” in calendar.properties, timer does not trigger and the state remains active.
On next business day, timer will resume at the beginning of the next working hour/day, after the non-working hour/holiday has ended. The timer is set to fire after one second of active business time.
Why Create a Custom Business Calendar?
This guide explains how to implement a custom business calendar allowing full flexibility.
kogito.processes.businessCalendar=org.kie.kogito.calendar.custom.CustomCalendar
Steps
BusinessCalendar
interface.The implementation should be a concrete class(not an interface or abstract class).kogito.processes.businessCalendar=org.kie.kogito.calendar.custom.CustomCalendar
in application.properties
to the fully qualified class name of the custom business calendar.calendar.properties
file within src/main/resources
to allow the CustomCalendar class
to be registered instead of the default BusinessCalendarImpl
provided out of the box.Implement your custom business logic
package org.kie.kogito.calendar.custom; import java.util.*; import org.kie.kogito.calendar.BusinessCalendar; /** * Custom Business Calendar Example. * Modify this class to implement your own scheduling logic. */ public class CustomCalendar implements BusinessCalendar { @Override public long calculateBusinessTimeAsDuration(String timeExpression) { // Implement custom logic to calculate business time duration // Note:The returned long value is in milliseconds. Duration can be set at least 1000 ms or longer to prevent immediate execution. return 1000; } @Override public Date calculateBusinessTimeAsDate(String timeExpression) { // Implement custom logic to return the scheduled date return new Date(); } }
To verify that your custom implementation works:
mvn clean compile spring-boot:run
or
mvn clean package
java -jar target/process-business-rules-springboot.jar