This is an automated email from the ASF dual-hosted git repository.

mweiler pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/incubator-kie-kogito-runtimes.git


The following commit(s) were added to refs/heads/main by this push:
     new ee5961bf83 [Incubator-kie-issues#2269] Providing support for cron 
timers (#4248)
ee5961bf83 is described below

commit ee5961bf830deaba0b5ff977c85931beed6447ee
Author: Abhiram Gundala <[email protected]>
AuthorDate: Thu Apr 16 16:29:53 2026 -0400

    [Incubator-kie-issues#2269] Providing support for cron timers (#4248)
    
    * Cron Timer Support
    
    * ported v8 tests
    
    * encapsulate cron repeatLimit in DateTimeUtils
    
    * removed getCronRepeatLimit override
    
    * fix cron timer test
    
    * Add getRemainingRepetitions to SimpleTimerTrigger
    
    * Rename to computeRemainingRepetitions avoid Jackson
---
 .../kie/kogito/timer/impl/SimpleTimerTrigger.java  |   7 ++
 .../org/jbpm/process/core/timer/DateTimeUtils.java |  27 +++++
 .../process/instance/AbstractProcessRuntime.java   |   7 +-
 .../instance/node/StateBasedNodeInstance.java      |  18 ++--
 .../kie/kogito/process/impl/AbstractProcess.java   |   7 +-
 .../bpmn2/event/BPMN2-BoundaryTimerCycleCron.bpmn2 | 116 +++++++++++++++++++++
 .../BPMN2-BoundaryTimerCycleCronVariable.bpmn2     | 116 +++++++++++++++++++++
 ...N2-MultipleBoundaryTimerCycleCronVariable.bpmn2 |  11 +-
 ...PMN2-IntermediateCatchEventTimerCycleCron.bpmn2 |   2 +-
 .../jbpm/bpmn2/start/BPMN2-TimerStartCron.bpmn2    |  62 +++++++++++
 .../java/org/jbpm/bpmn2/IntermediateEventTest.java |  80 +++++++++++++-
 .../test/java/org/jbpm/bpmn2/StartEventTest.java   |  18 ++++
 12 files changed, 457 insertions(+), 14 deletions(-)

diff --git 
a/api/kogito-timer/src/main/java/org/kie/kogito/timer/impl/SimpleTimerTrigger.java
 
b/api/kogito-timer/src/main/java/org/kie/kogito/timer/impl/SimpleTimerTrigger.java
index fad613f854..1134551666 100644
--- 
a/api/kogito-timer/src/main/java/org/kie/kogito/timer/impl/SimpleTimerTrigger.java
+++ 
b/api/kogito-timer/src/main/java/org/kie/kogito/timer/impl/SimpleTimerTrigger.java
@@ -230,6 +230,13 @@ public class SimpleTimerTrigger implements Trigger {
         return repeatCount == INDEFINITELY;
     }
 
+    public int computeRemainingRepetitions() {
+        if (isIndefinitely()) {
+            return -1;
+        }
+        return getRepeatCount() - getCurrentRepeatCount();
+    }
+
     /**
      * @return The number of executed repetitions for this timer, or -1 if the 
timer was configured with the indefinitely
      *         repeatCount = -1.
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/timer/DateTimeUtils.java 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/timer/DateTimeUtils.java
index 0093fcc002..4a110df526 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/timer/DateTimeUtils.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/timer/DateTimeUtils.java
@@ -18,14 +18,17 @@
  */
 package org.jbpm.process.core.timer;
 
+import java.text.ParseException;
 import java.time.Duration;
 import java.time.OffsetDateTime;
 import java.time.Period;
 import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
+import java.util.Date;
 import java.util.Objects;
 
 import org.drools.base.time.TimeUtils;
+import org.drools.core.time.impl.CronExpression;
 
 public class DateTimeUtils extends TimeUtils {
 
@@ -45,6 +48,30 @@ public class DateTimeUtils extends TimeUtils {
         return false;
     }
 
+    public static boolean isCronExpression(String dateTimeStr) {
+        return dateTimeStr != null && 
CronExpression.isValidExpression(dateTimeStr);
+    }
+
+    public static long[] parseCronAsRepeatableInterval(String cronExpression) {
+        try {
+            CronExpression cron = new CronExpression(cronExpression);
+            Date now = new Date();
+            Date firstFire = cron.getNextValidTimeAfter(now);
+            if (firstFire == null) {
+                throw new IllegalArgumentException("Cron expression will never 
fire: " + cronExpression);
+            }
+            long delay = firstFire.getTime() - now.getTime();
+            Date secondFire = cron.getNextValidTimeAfter(firstFire);
+            if (secondFire != null) {
+                long interval = secondFire.getTime() - firstFire.getTime();
+                return new long[] { Integer.MAX_VALUE, delay, interval };
+            }
+            return new long[] { 1, delay, delay };
+        } catch (ParseException e) {
+            throw new IllegalArgumentException("Invalid cron expression: " + 
cronExpression, e);
+        }
+    }
+
     public static long parseDateTime(String dateTimeStr) {
         OffsetDateTime dateTime = OffsetDateTime.parse(dateTimeStr, 
DateTimeFormatter.ISO_DATE_TIME);
         return dateTime.toInstant().toEpochMilli();
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/AbstractProcessRuntime.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/AbstractProcessRuntime.java
index 5bf4555802..9cf65396e4 100644
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/AbstractProcessRuntime.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/AbstractProcessRuntime.java
@@ -144,7 +144,12 @@ public abstract class AbstractProcessRuntime implements 
InternalProcessRuntime {
         switch (timer.getTimeType()) {
             case Timer.TIME_CYCLE:
                 // when using ISO date/time period is not set
-                long[] repeatValues = 
DateTimeUtils.parseRepeatableDateTime(timer.getDelay());
+                long[] repeatValues;
+                if (DateTimeUtils.isCronExpression(timer.getDelay())) {
+                    repeatValues = 
DateTimeUtils.parseCronAsRepeatableInterval(timer.getDelay());
+                } else {
+                    repeatValues = 
DateTimeUtils.parseRepeatableDateTime(timer.getDelay());
+                }
                 if (repeatValues.length == 3) {
                     int repeatLimit = repeatValues[0] < 0 ? 0 : (int) 
repeatValues[0];
                     return DurationExpirationTime.repeat(repeatValues[1], 
repeatValues[2], repeatLimit);
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/StateBasedNodeInstance.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/StateBasedNodeInstance.java
index b6a4c21197..7e0aabd46f 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/StateBasedNodeInstance.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/StateBasedNodeInstance.java
@@ -149,6 +149,10 @@ public abstract class StateBasedNodeInstance extends 
ExtendedNodeInstanceImpl im
 
                     String tempDelay = 
resolveTimerExpression(timer.getDelay());
                     String tempPeriod = 
resolveTimerExpression(timer.getPeriod());
+                    if (DateTimeUtils.isCronExpression(tempDelay)) {
+                        long[] cronValues = 
DateTimeUtils.parseCronAsRepeatableInterval(tempDelay);
+                        return DurationExpirationTime.repeat(cronValues[1], 
cronValues[2], (int) cronValues[0]);
+                    }
                     if (DateTimeUtils.isRepeatable(tempDelay)) {
                         String[] values = 
DateTimeUtils.parseISORepeatable(tempDelay);
                         String tempRepeatLimit = values[0];
@@ -207,14 +211,16 @@ public abstract class StateBasedNodeInstance extends 
ExtendedNodeInstanceImpl im
                     }
                 } else {
                     String resolvedDelay = 
resolveTimerExpression(timer.getDelay());
-
                     // when using ISO date/time period is not set
                     long[] repeatValues = null;
-                    try {
-                        repeatValues = 
DateTimeUtils.parseRepeatableDateTime(timer.getDelay());
-                    } catch (RuntimeException e) {
-                        // cannot parse delay, trying to interpret it
-                        repeatValues = 
DateTimeUtils.parseRepeatableDateTime(resolvedDelay);
+                    if (DateTimeUtils.isCronExpression(resolvedDelay)) {
+                        repeatValues = 
DateTimeUtils.parseCronAsRepeatableInterval(resolvedDelay);
+                    } else {
+                        try {
+                            repeatValues = 
DateTimeUtils.parseRepeatableDateTime(timer.getDelay());
+                        } catch (RuntimeException e) {
+                            repeatValues = 
DateTimeUtils.parseRepeatableDateTime(resolvedDelay);
+                        }
                     }
                     if (repeatValues.length == 3) {
                         int parsedReapedCount = (int) repeatValues[0];
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcess.java 
b/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcess.java
index cce17f0560..9e7e8648cb 100644
--- 
a/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcess.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcess.java
@@ -272,7 +272,12 @@ public abstract class AbstractProcess<T extends Model> 
implements Process<T>, Pr
         switch (timer.getTimeType()) {
             case Timer.TIME_CYCLE:
                 // when using ISO date/time period is not set
-                long[] repeatValues = 
DateTimeUtils.parseRepeatableDateTime(timer.getDelay());
+                long[] repeatValues;
+                if (DateTimeUtils.isCronExpression(timer.getDelay())) {
+                    repeatValues = 
DateTimeUtils.parseCronAsRepeatableInterval(timer.getDelay());
+                } else {
+                    repeatValues = 
DateTimeUtils.parseRepeatableDateTime(timer.getDelay());
+                }
                 if (repeatValues.length == 3) {
                     int parsedReapedCount = (int) repeatValues[0];
                     if (parsedReapedCount <= -1) {
diff --git 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/event/BPMN2-BoundaryTimerCycleCron.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/event/BPMN2-BoundaryTimerCycleCron.bpmn2
new file mode 100644
index 0000000000..806ba21760
--- /dev/null
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/event/BPMN2-BoundaryTimerCycleCron.bpmn2
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns="http://www.omg.org/bpmn20"; 
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"; 
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"; 
xmlns:bpsim="http://www.bpsim.org/schemas/1.0"; 
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"; 
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"; 
xmlns:drools="http://www.jboss.org/drools"; id="_erIygJZ7EeSDh8PHobjSSB" 
xsi:schemaLocation="http://www.omg.org/spec/BPMN/201 [...]
+  <bpmn2:itemDefinition id="_cronStrItem" structureRef="String"/>
+  <bpmn2:itemDefinition id="_completeItem" structureRef="String"/>
+  <bpmn2:process id="BoundaryTimerCycleCron" 
drools:packageName="org.jbpm.bpmn2.event" drools:version="1.0" 
name="BoundaryTimerCycleCron" isExecutable="true">
+    <bpmn2:property id="cronStr" itemSubjectRef="_cronStrItem"/>
+    <bpmn2:property id="complete" itemSubjectRef="_completeItem"/>
+    <bpmn2:startEvent id="processStartEvent" drools:bgcolor="#9acd32" 
drools:selectable="true" name="">
+      <bpmn2:outgoing>_6BB13960-7EC2-466D-AD11-3128F7EDDE8F</bpmn2:outgoing>
+    </bpmn2:startEvent>
+    <bpmn2:userTask id="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6" 
drools:selectable="true" drools:scriptFormat="http://www.java.com/java"; 
name="Finish Work">
+      <bpmn2:extensionElements>
+        <drools:onEntry-script scriptFormat="http://www.java.com/java";>
+          <drools:script><![CDATA[System.out.println("Finish 
Work");]]></drools:script>
+        </drools:onEntry-script>
+      </bpmn2:extensionElements>
+      <bpmn2:incoming>_6BB13960-7EC2-466D-AD11-3128F7EDDE8F</bpmn2:incoming>
+      <bpmn2:outgoing>_0819806F-6B1A-4058-B848-CE4938E0DFA7</bpmn2:outgoing>
+      <bpmn2:potentialOwner id="_erIygZZ7EeSDh8PHobjSSB">
+        <bpmn2:resourceAssignmentExpression id="_erIygpZ7EeSDh8PHobjSSB">
+          <bpmn2:formalExpression 
id="_erIyg5Z7EeSDh8PHobjSSB">john</bpmn2:formalExpression>
+        </bpmn2:resourceAssignmentExpression>
+      </bpmn2:potentialOwner>
+    </bpmn2:userTask>
+    <bpmn2:endEvent id="_861C71C8-12C0-4EBB-9536-1537FB045A1D" 
drools:bgcolor="#ff6347" drools:selectable="true" name="">
+      <bpmn2:incoming>_0819806F-6B1A-4058-B848-CE4938E0DFA7</bpmn2:incoming>
+      <bpmn2:terminateEventDefinition id="_erIyhJZ7EeSDh8PHobjSSB"/>
+    </bpmn2:endEvent>
+    <bpmn2:sequenceFlow id="_6BB13960-7EC2-466D-AD11-3128F7EDDE8F" 
drools:bgcolor="#000000" drools:selectable="true" sourceRef="processStartEvent" 
targetRef="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6"/>
+    <bpmn2:userTask id="_78E7D740-28D7-49F3-9A4D-801C92F6EDD9" 
drools:selectable="true" drools:scriptFormat="http://www.java.com/java"; 
name="Send Update Timer">
+      <bpmn2:extensionElements>
+        <drools:onEntry-script scriptFormat="http://www.java.com/java";>
+          <drools:script><![CDATA[System.out.println("Sending 
Update...");]]></drools:script>
+        </drools:onEntry-script>
+      </bpmn2:extensionElements>
+      <bpmn2:incoming>_1206D165-6704-439E-99E6-7A02989A8C3C</bpmn2:incoming>
+      <bpmn2:outgoing>_CC158D9E-0478-4474-8A21-D638565EC92A</bpmn2:outgoing>
+      <bpmn2:potentialOwner id="_erIyhZZ7EeSDh8PHobjSSB">
+        <bpmn2:resourceAssignmentExpression id="_erIyhpZ7EeSDh8PHobjSSB">
+          <bpmn2:formalExpression 
id="_erIyh5Z7EeSDh8PHobjSSB">john</bpmn2:formalExpression>
+        </bpmn2:resourceAssignmentExpression>
+      </bpmn2:potentialOwner>
+    </bpmn2:userTask>
+    <bpmn2:sequenceFlow id="_1206D165-6704-439E-99E6-7A02989A8C3C" 
drools:bgcolor="#000000" drools:selectable="true" 
sourceRef="_8B5EE6E3-73EE-477D-8CC5-96F7C01DA7F0" 
targetRef="_78E7D740-28D7-49F3-9A4D-801C92F6EDD9"/>
+    <bpmn2:endEvent id="_A6951F30-BBCD-4A26-9368-00622D6358C3" 
drools:bgcolor="#ff6347" drools:selectable="true" name="">
+      <bpmn2:incoming>_CC158D9E-0478-4474-8A21-D638565EC92A</bpmn2:incoming>
+    </bpmn2:endEvent>
+    <bpmn2:sequenceFlow id="_CC158D9E-0478-4474-8A21-D638565EC92A" 
drools:bgcolor="#000000" drools:selectable="true" 
sourceRef="_78E7D740-28D7-49F3-9A4D-801C92F6EDD9" 
targetRef="_A6951F30-BBCD-4A26-9368-00622D6358C3"/>
+    <bpmn2:sequenceFlow id="_0819806F-6B1A-4058-B848-CE4938E0DFA7" 
drools:bgcolor="#000000" drools:selectable="true" 
sourceRef="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6" 
targetRef="_861C71C8-12C0-4EBB-9536-1537FB045A1D"/>
+    <bpmn2:boundaryEvent id="_8B5EE6E3-73EE-477D-8CC5-96F7C01DA7F0" 
drools:bgcolor="#f5deb3" drools:selectable="true" drools:bordercolor="#a0522d" 
drools:boundaryca="false" name="Send Update Timer" 
attachedToRef="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6" cancelActivity="false">
+      <bpmn2:outgoing>_1206D165-6704-439E-99E6-7A02989A8C3C</bpmn2:outgoing>
+      <bpmn2:timerEventDefinition id="_erIyiJZ7EeSDh8PHobjSSB">
+        <bpmn2:timeCycle xsi:type="bpmn2:tFormalExpression" 
id="_erIyiZZ7EeSDh8PHobjSSB" language="cron">0/1 * * * * ?</bpmn2:timeCycle>
+      </bpmn2:timerEventDefinition>
+    </bpmn2:boundaryEvent>
+  </bpmn2:process>
+  <bpmndi:BPMNDiagram id="_erJZkJZ7EeSDh8PHobjSSB">
+    <bpmndi:BPMNPlane id="_erJZkZZ7EeSDh8PHobjSSB" 
bpmnElement="BoundaryTimerCycleCron">
+      <bpmndi:BPMNShape id="_erJZkpZ7EeSDh8PHobjSSB" 
bpmnElement="processStartEvent">
+        <dc:Bounds height="30.0" width="30.0" x="60.0" y="105.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="_erJZk5Z7EeSDh8PHobjSSB" 
bpmnElement="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6">
+        <dc:Bounds height="80.0" width="100.0" x="195.0" y="80.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="_erJZlJZ7EeSDh8PHobjSSB" 
bpmnElement="_861C71C8-12C0-4EBB-9536-1537FB045A1D">
+        <dc:Bounds height="28.0" width="28.0" x="435.0" y="106.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="_erJZlZZ7EeSDh8PHobjSSB" 
bpmnElement="_6BB13960-7EC2-466D-AD11-3128F7EDDE8F">
+        <di:waypoint xsi:type="dc:Point" x="75.0" y="120.0"/>
+        <di:waypoint xsi:type="dc:Point" x="245.0" y="120.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_erJZlpZ7EeSDh8PHobjSSB" 
bpmnElement="_78E7D740-28D7-49F3-9A4D-801C92F6EDD9">
+        <dc:Bounds height="80.0" width="100.0" x="225.0" y="240.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="_erJZl5Z7EeSDh8PHobjSSB" 
bpmnElement="_1206D165-6704-439E-99E6-7A02989A8C3C">
+        <di:waypoint xsi:type="dc:Point" x="196.0" y="160.0"/>
+        <di:waypoint xsi:type="dc:Point" x="196.0" y="207.0"/>
+        <di:waypoint xsi:type="dc:Point" x="275.0" y="207.0"/>
+        <di:waypoint xsi:type="dc:Point" x="275.0" y="280.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_erJZmJZ7EeSDh8PHobjSSB" 
bpmnElement="_A6951F30-BBCD-4A26-9368-00622D6358C3">
+        <dc:Bounds height="28.0" width="28.0" x="370.0" y="266.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="_erJZmZZ7EeSDh8PHobjSSB" 
bpmnElement="_CC158D9E-0478-4474-8A21-D638565EC92A">
+        <di:waypoint xsi:type="dc:Point" x="275.0" y="280.0"/>
+        <di:waypoint xsi:type="dc:Point" x="384.0" y="280.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="_erJZmpZ7EeSDh8PHobjSSB" 
bpmnElement="_0819806F-6B1A-4058-B848-CE4938E0DFA7">
+        <di:waypoint xsi:type="dc:Point" x="245.0" y="120.0"/>
+        <di:waypoint xsi:type="dc:Point" x="449.0" y="120.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_erJZm5Z7EeSDh8PHobjSSB" 
bpmnElement="_8B5EE6E3-73EE-477D-8CC5-96F7C01DA7F0">
+        <dc:Bounds height="30.0" width="30.0" x="181.0" y="145.0"/>
+      </bpmndi:BPMNShape>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn2:definitions>
diff --git 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/event/BPMN2-BoundaryTimerCycleCronVariable.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/event/BPMN2-BoundaryTimerCycleCronVariable.bpmn2
new file mode 100644
index 0000000000..3884a53a7f
--- /dev/null
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/event/BPMN2-BoundaryTimerCycleCronVariable.bpmn2
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns="http://www.omg.org/bpmn20"; 
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"; 
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"; 
xmlns:bpsim="http://www.bpsim.org/schemas/1.0"; 
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"; 
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"; 
xmlns:drools="http://www.jboss.org/drools"; id="_erIygJZ7EeSDh8PHobjSSC" 
xsi:schemaLocation="http://www.omg.org/spec/BPMN/201 [...]
+  <bpmn2:itemDefinition id="_cronStrItem" structureRef="String"/>
+  <bpmn2:itemDefinition id="_completeItem" structureRef="String"/>
+  <bpmn2:process id="BoundaryTimerCycleCronVariable" 
drools:packageName="org.jbpm.bpmn2.event" drools:version="1.0" 
name="BoundaryTimerCycleCronVariable" isExecutable="true">
+    <bpmn2:property id="cronStr" itemSubjectRef="_cronStrItem"/>
+    <bpmn2:property id="complete" itemSubjectRef="_completeItem"/>
+    <bpmn2:startEvent id="processStartEvent" drools:bgcolor="#9acd32" 
drools:selectable="true" name="">
+      <bpmn2:outgoing>_6BB13960-7EC2-466D-AD11-3128F7EDDE8F</bpmn2:outgoing>
+    </bpmn2:startEvent>
+    <bpmn2:userTask id="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6" 
drools:selectable="true" drools:scriptFormat="http://www.java.com/java"; 
name="Finish Work">
+      <bpmn2:extensionElements>
+        <drools:onEntry-script scriptFormat="http://www.java.com/java";>
+          <drools:script><![CDATA[System.out.println("Finish 
Work");]]></drools:script>
+        </drools:onEntry-script>
+      </bpmn2:extensionElements>
+      <bpmn2:incoming>_6BB13960-7EC2-466D-AD11-3128F7EDDE8F</bpmn2:incoming>
+      <bpmn2:outgoing>_0819806F-6B1A-4058-B848-CE4938E0DFA7</bpmn2:outgoing>
+      <bpmn2:potentialOwner id="_erIygZZ7EeSDh8PHobjSSC">
+        <bpmn2:resourceAssignmentExpression id="_erIygpZ7EeSDh8PHobjSSC">
+          <bpmn2:formalExpression 
id="_erIyg5Z7EeSDh8PHobjSSC">john</bpmn2:formalExpression>
+        </bpmn2:resourceAssignmentExpression>
+      </bpmn2:potentialOwner>
+    </bpmn2:userTask>
+    <bpmn2:endEvent id="_861C71C8-12C0-4EBB-9536-1537FB045A1D" 
drools:bgcolor="#ff6347" drools:selectable="true" name="">
+      <bpmn2:incoming>_0819806F-6B1A-4058-B848-CE4938E0DFA7</bpmn2:incoming>
+      <bpmn2:terminateEventDefinition id="_erIyhJZ7EeSDh8PHobjSSC"/>
+    </bpmn2:endEvent>
+    <bpmn2:sequenceFlow id="_6BB13960-7EC2-466D-AD11-3128F7EDDE8F" 
drools:bgcolor="#000000" drools:selectable="true" sourceRef="processStartEvent" 
targetRef="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6"/>
+    <bpmn2:userTask id="_78E7D740-28D7-49F3-9A4D-801C92F6EDD9" 
drools:selectable="true" drools:scriptFormat="http://www.java.com/java"; 
name="Send Update Timer">
+      <bpmn2:extensionElements>
+        <drools:onEntry-script scriptFormat="http://www.java.com/java";>
+          <drools:script><![CDATA[System.out.println("Sending 
Update...");]]></drools:script>
+        </drools:onEntry-script>
+      </bpmn2:extensionElements>
+      <bpmn2:incoming>_1206D165-6704-439E-99E6-7A02989A8C3C</bpmn2:incoming>
+      <bpmn2:outgoing>_CC158D9E-0478-4474-8A21-D638565EC92A</bpmn2:outgoing>
+      <bpmn2:potentialOwner id="_erIyhZZ7EeSDh8PHobjSSC">
+        <bpmn2:resourceAssignmentExpression id="_erIyhpZ7EeSDh8PHobjSSC">
+          <bpmn2:formalExpression 
id="_erIyh5Z7EeSDh8PHobjSSC">john</bpmn2:formalExpression>
+        </bpmn2:resourceAssignmentExpression>
+      </bpmn2:potentialOwner>
+    </bpmn2:userTask>
+    <bpmn2:sequenceFlow id="_1206D165-6704-439E-99E6-7A02989A8C3C" 
drools:bgcolor="#000000" drools:selectable="true" 
sourceRef="_8B5EE6E3-73EE-477D-8CC5-96F7C01DA7F0" 
targetRef="_78E7D740-28D7-49F3-9A4D-801C92F6EDD9"/>
+    <bpmn2:endEvent id="_A6951F30-BBCD-4A26-9368-00622D6358C3" 
drools:bgcolor="#ff6347" drools:selectable="true" name="">
+      <bpmn2:incoming>_CC158D9E-0478-4474-8A21-D638565EC92A</bpmn2:incoming>
+    </bpmn2:endEvent>
+    <bpmn2:sequenceFlow id="_CC158D9E-0478-4474-8A21-D638565EC92A" 
drools:bgcolor="#000000" drools:selectable="true" 
sourceRef="_78E7D740-28D7-49F3-9A4D-801C92F6EDD9" 
targetRef="_A6951F30-BBCD-4A26-9368-00622D6358C3"/>
+    <bpmn2:sequenceFlow id="_0819806F-6B1A-4058-B848-CE4938E0DFA7" 
drools:bgcolor="#000000" drools:selectable="true" 
sourceRef="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6" 
targetRef="_861C71C8-12C0-4EBB-9536-1537FB045A1D"/>
+    <bpmn2:boundaryEvent id="_8B5EE6E3-73EE-477D-8CC5-96F7C01DA7F0" 
drools:bgcolor="#f5deb3" drools:selectable="true" drools:bordercolor="#a0522d" 
drools:boundaryca="false" name="Send Update Timer" 
attachedToRef="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6" cancelActivity="false">
+      <bpmn2:outgoing>_1206D165-6704-439E-99E6-7A02989A8C3C</bpmn2:outgoing>
+      <bpmn2:timerEventDefinition id="_erIyiJZ7EeSDh8PHobjSSC">
+        <bpmn2:timeCycle xsi:type="bpmn2:tFormalExpression" 
id="_erIyiZZ7EeSDh8PHobjSSC" language="cron">#{cronStr}</bpmn2:timeCycle>
+      </bpmn2:timerEventDefinition>
+    </bpmn2:boundaryEvent>
+  </bpmn2:process>
+  <bpmndi:BPMNDiagram id="_erJZkJZ7EeSDh8PHobjSSC">
+    <bpmndi:BPMNPlane id="_erJZkZZ7EeSDh8PHobjSSC" 
bpmnElement="BoundaryTimerCycleCronVariable">
+      <bpmndi:BPMNShape id="_erJZkpZ7EeSDh8PHobjSSC" 
bpmnElement="processStartEvent">
+        <dc:Bounds height="30.0" width="30.0" x="60.0" y="105.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="_erJZk5Z7EeSDh8PHobjSSC" 
bpmnElement="_77A94B54-8B7C-4F8A-84EE-C1D310A343A6">
+        <dc:Bounds height="80.0" width="100.0" x="195.0" y="80.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="_erJZlJZ7EeSDh8PHobjSSC" 
bpmnElement="_861C71C8-12C0-4EBB-9536-1537FB045A1D">
+        <dc:Bounds height="28.0" width="28.0" x="435.0" y="106.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="_erJZlZZ7EeSDh8PHobjSSC" 
bpmnElement="_6BB13960-7EC2-466D-AD11-3128F7EDDE8F">
+        <di:waypoint xsi:type="dc:Point" x="75.0" y="120.0"/>
+        <di:waypoint xsi:type="dc:Point" x="245.0" y="120.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_erJZlpZ7EeSDh8PHobjSSC" 
bpmnElement="_78E7D740-28D7-49F3-9A4D-801C92F6EDD9">
+        <dc:Bounds height="80.0" width="100.0" x="225.0" y="240.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="_erJZl5Z7EeSDh8PHobjSSC" 
bpmnElement="_1206D165-6704-439E-99E6-7A02989A8C3C">
+        <di:waypoint xsi:type="dc:Point" x="196.0" y="160.0"/>
+        <di:waypoint xsi:type="dc:Point" x="196.0" y="207.0"/>
+        <di:waypoint xsi:type="dc:Point" x="275.0" y="207.0"/>
+        <di:waypoint xsi:type="dc:Point" x="275.0" y="280.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_erJZmJZ7EeSDh8PHobjSSC" 
bpmnElement="_A6951F30-BBCD-4A26-9368-00622D6358C3">
+        <dc:Bounds height="28.0" width="28.0" x="370.0" y="266.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="_erJZmZZ7EeSDh8PHobjSSC" 
bpmnElement="_CC158D9E-0478-4474-8A21-D638565EC92A">
+        <di:waypoint xsi:type="dc:Point" x="275.0" y="280.0"/>
+        <di:waypoint xsi:type="dc:Point" x="384.0" y="280.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="_erJZmpZ7EeSDh8PHobjSSC" 
bpmnElement="_0819806F-6B1A-4058-B848-CE4938E0DFA7">
+        <di:waypoint xsi:type="dc:Point" x="245.0" y="120.0"/>
+        <di:waypoint xsi:type="dc:Point" x="449.0" y="120.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_erJZm5Z7EeSDh8PHobjSSC" 
bpmnElement="_8B5EE6E3-73EE-477D-8CC5-96F7C01DA7F0">
+        <dc:Bounds height="30.0" width="30.0" x="181.0" y="145.0"/>
+      </bpmndi:BPMNShape>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn2:definitions>
diff --git 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultipleBoundaryTimerCycleCronVariable.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/event/BPMN2-MultipleBoundaryTimerCycleCronVariable.bpmn2
old mode 100755
new mode 100644
similarity index 97%
rename from 
jbpm/jbpm-tests/src/test/resources/BPMN2-MultipleBoundaryTimerCycleCronVariable.bpmn2
rename to 
jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/event/BPMN2-MultipleBoundaryTimerCycleCronVariable.bpmn2
index 7423498a34..6eb01e23dc
--- 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultipleBoundaryTimerCycleCronVariable.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/event/BPMN2-MultipleBoundaryTimerCycleCronVariable.bpmn2
@@ -38,7 +38,7 @@
   <bpmn2:itemDefinition id="ItemDefinition_14" isCollection="false"/>
   <bpmn2:itemDefinition id="ItemDefinition_15" isCollection="false"/>
   <bpmn2:itemDefinition id="ItemDefinition_16" isCollection="false"/>
-  <bpmn2:process id="boundaryTimerCycleCron" drools:packageName="org.jbpm" 
drools:version="1.0" name="Test_Cron" isExecutable="true">
+  <bpmn2:process id="MultipleBoundaryTimerCycleCronVariable" 
drools:packageName="org.jbpm.bpmn2.event" drools:version="1.0" name="Test_Cron" 
isExecutable="true">
     <bpmn2:property id="cronStr" itemSubjectRef="_cronStrItem" name="cronStr"/>
     <bpmn2:property id="complete" itemSubjectRef="_completeItem" 
name="complete"/>
     <bpmn2:startEvent id="processStartEvent" drools:bgcolor="#9acd32" 
drools:selectable="true" name="">
@@ -174,10 +174,15 @@
       <bpmn2:dataInputAssociation id="DataInputAssociation_9">
         <bpmn2:targetRef>DataInput_9</bpmn2:targetRef>
       </bpmn2:dataInputAssociation>
+      <bpmn2:potentialOwner id="_erIyhZZ7EeSDh8PHobjSSA_2">
+        <bpmn2:resourceAssignmentExpression id="_erIyhpZ7EeSDh8PHobjSSA_2">
+          <bpmn2:formalExpression 
id="_erIyh5Z7EeSDh8PHobjSSA_2">john</bpmn2:formalExpression>
+        </bpmn2:resourceAssignmentExpression>
+      </bpmn2:potentialOwner>
     </bpmn2:userTask>
   </bpmn2:process>
   <bpmndi:BPMNDiagram id="_erJZkJZ7EeSDh8PHobjSSA">
-    <bpmndi:BPMNPlane id="_erJZkZZ7EeSDh8PHobjSSA" 
bpmnElement="boundaryTimerCycleCron">
+    <bpmndi:BPMNPlane id="_erJZkZZ7EeSDh8PHobjSSA" 
bpmnElement="MultipleBoundaryTimerCycleCronVariable">
       <bpmndi:BPMNShape id="_erJZkpZ7EeSDh8PHobjSSA" 
bpmnElement="processStartEvent">
         <dc:Bounds height="30.0" width="30.0" x="60.0" y="105.0"/>
         <bpmndi:BPMNLabel id="BPMNLabel_1"/>
@@ -266,4 +271,4 @@
       </bpmndi:BPMNEdge>
     </bpmndi:BPMNPlane>
   </bpmndi:BPMNDiagram>
-</bpmn2:definitions>
\ No newline at end of file
+</bpmn2:definitions>
diff --git 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/intermediate/BPMN2-IntermediateCatchEventTimerCycleCron.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/intermediate/BPMN2-IntermediateCatchEventTimerCycleCron.bpmn2
index 5b49feb3db..99cddc6d6d 100755
--- 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/intermediate/BPMN2-IntermediateCatchEventTimerCycleCron.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/intermediate/BPMN2-IntermediateCatchEventTimerCycleCron.bpmn2
@@ -41,7 +41,7 @@
     <startEvent id="_1" name="StartProcess" />
     <intermediateCatchEvent id="_3" name="timer" >
       <timerEventDefinition>
-        <timeCycle language="iso">R3/PT1S</timeCycle>
+        <timeCycle language="cron">0/1 * * * * ?</timeCycle>
       </timerEventDefinition>
     </intermediateCatchEvent>
     <scriptTask id="_4" name="Event" >
diff --git 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/start/BPMN2-TimerStartCron.bpmn2 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/start/BPMN2-TimerStartCron.bpmn2
new file mode 100644
index 0000000000..e450c8408f
--- /dev/null
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/start/BPMN2-TimerStartCron.bpmn2
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"; 
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"; 
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"; 
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"; 
xmlns:tns="http://www.jboss.org/drools"; 
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" 
id="Definition" expressionLanguage="http://www.mvel.org/2.0"; 
targetNamespace="http://www.example.org/ [...]
+  <process id="TimerStartCron" tns:packageName="org.jbpm.bpmn2.start" 
name="Minimal Process" isExecutable="true" processType="Private">
+    <startEvent id="_1" name="StartProcess">
+      <outgoing>_1-_2</outgoing>
+      <timerEventDefinition id="TimerEventDefinition_1">
+        <timeCycle xsi:type="tFormalExpression" id="FormalExpression_1" 
language="cron">0/1 * * * * ?</timeCycle>
+      </timerEventDefinition>
+    </startEvent>
+    <scriptTask id="_2" name="Hello">
+      <incoming>_1-_2</incoming>
+      <outgoing>_2-_3</outgoing>
+      <script>System.out.println(&quot;Triggered ...&quot;);</script>
+    </scriptTask>
+    <endEvent id="_3" name="EndProcess">
+      <incoming>_2-_3</incoming>
+      <terminateEventDefinition id="TerminateEventDefinition_1"/>
+    </endEvent>
+    <sequenceFlow id="_1-_2" sourceRef="_1" targetRef="_2"/>
+    <sequenceFlow id="_2-_3" sourceRef="_2" targetRef="_3"/>
+  </process>
+  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+    <bpmndi:BPMNPlane id="BPMNPlane_Process_1" bpmnElement="TimerStartCron">
+      <bpmndi:BPMNShape id="BPMNShape_StartEvent_1" bpmnElement="_1">
+        <dc:Bounds height="48.0" width="48.0" x="16.0" y="16.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_ScriptTask_1" bpmnElement="_2">
+        <dc:Bounds height="50.0" width="110.0" x="96.0" y="16.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_EndEvent_1" bpmnElement="_3">
+        <dc:Bounds height="48.0" width="48.0" x="208.0" y="16.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="_1-_2">
+        <di:waypoint xsi:type="dc:Point" x="52.0" y="34.0"/>
+        <di:waypoint xsi:type="dc:Point" x="96.0" y="41.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_2" bpmnElement="_2-_3">
+        <di:waypoint xsi:type="dc:Point" x="206.0" y="41.0"/>
+        <di:waypoint xsi:type="dc:Point" x="208.0" y="34.0"/>
+      </bpmndi:BPMNEdge>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</definitions>
diff --git 
a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java 
b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
index 92b381a5d4..6c87bdfdff 100755
--- a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
+++ b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
@@ -37,10 +37,16 @@ import 
org.jbpm.bpmn2.activity.BoundarySignalEventOnTaskWithTransformationModel;
 import 
org.jbpm.bpmn2.activity.BoundarySignalEventOnTaskWithTransformationProcess;
 import org.jbpm.bpmn2.event.BoundarySignalWithNameEventOnTaskModel;
 import org.jbpm.bpmn2.event.BoundarySignalWithNameEventOnTaskProcess;
+import org.jbpm.bpmn2.event.BoundaryTimerCycleCronModel;
+import org.jbpm.bpmn2.event.BoundaryTimerCycleCronProcess;
+import org.jbpm.bpmn2.event.BoundaryTimerCycleCronVariableModel;
+import org.jbpm.bpmn2.event.BoundaryTimerCycleCronVariableProcess;
 import org.jbpm.bpmn2.event.BoundaryTimerCycleISOModel;
 import org.jbpm.bpmn2.event.BoundaryTimerCycleISOProcess;
 import org.jbpm.bpmn2.event.BoundaryTimerCycleISOVariableModel;
 import org.jbpm.bpmn2.event.BoundaryTimerCycleISOVariableProcess;
+import org.jbpm.bpmn2.event.MultipleBoundaryTimerCycleCronVariableModel;
+import org.jbpm.bpmn2.event.MultipleBoundaryTimerCycleCronVariableProcess;
 import org.jbpm.bpmn2.intermediate.*;
 import org.jbpm.bpmn2.loop.MultiInstanceLoopBoundaryTimerModel;
 import org.jbpm.bpmn2.loop.MultiInstanceLoopBoundaryTimerProcess;
@@ -208,6 +214,75 @@ public class IntermediateEventTest extends 
JbpmBpmn2TestCase {
                 
.isPresent().get().extracting(WorkflowProcessInstance::getState).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
     }
 
+    @Test
+    public void testTimerBoundaryEventCronCycle() {
+        Application app = ProcessTestHelper.newApplication();
+        NodeLeftCountDownProcessEventListener listener = new 
NodeLeftCountDownProcessEventListener("Send Update Timer", 3);
+        ProcessTestHelper.registerHandler(app, "Human Task", new 
TestUserTaskWorkItemHandler());
+        ProcessTestHelper.registerProcessEventListener(app, listener);
+        org.kie.kogito.process.Process<BoundaryTimerCycleCronModel> definition 
= BoundaryTimerCycleCronProcess.newProcess(app);
+        org.kie.kogito.process.ProcessInstance<BoundaryTimerCycleCronModel> 
instance = definition
+                .createInstance(definition.createModel());
+        instance.start();
+        listener.waitTillCompleted();
+        List<WorkItem> allWorkItems = instance.workItems();
+        assertThat(allWorkItems).hasSize(4);
+        List<WorkItem> workItems = allWorkItems.stream().filter(e -> "Finish 
Work".equals(e.getName())).toList();
+        assertThat(workItems).hasSize(1);
+        instance.completeWorkItem(workItems.get(0).getId(), 
Collections.emptyMap());
+        assertThat(ProcessTestHelper.findRemovedInstance(app, instance.id()))
+                
.isPresent().get().extracting(WorkflowProcessInstance::getState).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+    }
+
+    @Test
+    public void testTimerBoundaryEventCronCycleVariable() {
+        Application app = ProcessTestHelper.newApplication();
+        NodeLeftCountDownProcessEventListener listener = new 
NodeLeftCountDownProcessEventListener("Send Update Timer", 3);
+        ProcessTestHelper.registerHandler(app, "Human Task", new 
TestUserTaskWorkItemHandler());
+        ProcessTestHelper.registerProcessEventListener(app, listener);
+        org.kie.kogito.process.Process<BoundaryTimerCycleCronVariableModel> 
definition = BoundaryTimerCycleCronVariableProcess.newProcess(app);
+        BoundaryTimerCycleCronVariableModel model = definition.createModel();
+        model.setCronStr("0/1 * * * * ?");
+        
org.kie.kogito.process.ProcessInstance<BoundaryTimerCycleCronVariableModel> 
instance = definition
+                .createInstance(model);
+        instance.start();
+        listener.waitTillCompleted();
+        List<WorkItem> allWorkItems = instance.workItems();
+        assertThat(allWorkItems).hasSize(4);
+        List<WorkItem> workItems = allWorkItems.stream().filter(e -> "Finish 
Work".equals(e.getName())).toList();
+        assertThat(workItems).hasSize(1);
+        instance.completeWorkItem(workItems.get(0).getId(), 
Collections.emptyMap());
+        assertThat(ProcessTestHelper.findRemovedInstance(app, instance.id()))
+                
.isPresent().get().extracting(WorkflowProcessInstance::getState).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+    }
+
+    @Test
+    public void testMultipleTimerBoundaryEventCronCycleVariable() {
+        Application app = ProcessTestHelper.newApplication();
+        NodeLeftCountDownProcessEventListener listener = new 
NodeLeftCountDownProcessEventListener("Send Update Timer", 2);
+        ProcessTestHelper.registerHandler(app, "Human Task", new 
TestUserTaskWorkItemHandler());
+        ProcessTestHelper.registerProcessEventListener(app, listener);
+        
org.kie.kogito.process.Process<MultipleBoundaryTimerCycleCronVariableModel> 
definition =
+                MultipleBoundaryTimerCycleCronVariableProcess.newProcess(app);
+        MultipleBoundaryTimerCycleCronVariableModel model = 
definition.createModel();
+        model.setCronStr("0/1 * * * * ?");
+        
org.kie.kogito.process.ProcessInstance<MultipleBoundaryTimerCycleCronVariableModel>
 instance =
+                definition.createInstance(model);
+        instance.start();
+        List<WorkItem> workItems = instance.workItems();
+        assertThat(workItems).isNotNull();
+        assertThat(workItems.size()).isEqualTo(1);
+        listener.waitTillCompleted();
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_ACTIVE);
+        workItems = instance.workItems();
+        assertThat(workItems).hasSizeGreaterThanOrEqualTo(3);
+        List<WorkItem> finishWork = workItems.stream().filter(e -> "Finish 
Work".equals(e.getName())).toList();
+        assertThat(finishWork).hasSize(1);
+        instance.completeWorkItem(finishWork.get(0).getId(), 
Collections.emptyMap());
+        assertThat(ProcessTestHelper.findRemovedInstance(app, instance.id()))
+                
.isPresent().get().extracting(WorkflowProcessInstance::getState).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+    }
+
     @Test
     public void testSignalBoundaryEvent() {
         Application app = ProcessTestHelper.newApplication();
@@ -1978,8 +2053,9 @@ public class IntermediateEventTest extends 
JbpmBpmn2TestCase {
                 .createInstance(definition.createModel());
         instance.start();
         latch.await(5, TimeUnit.SECONDS);
-        assertThat(ProcessTestHelper.findRemovedInstance(app, instance.id()))
-                
.isPresent().get().extracting(WorkflowProcessInstance::getState).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_ACTIVE);
+        instance.abort();
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_ABORTED);
     }
 
     @Test
diff --git a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/StartEventTest.java 
b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/StartEventTest.java
index 61df99b34c..b93c6dc2f9 100755
--- a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/StartEventTest.java
+++ b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/StartEventTest.java
@@ -195,6 +195,24 @@ public class StartEventTest extends JbpmBpmn2TestCase {
         assertThat(startedInstances).hasSize(6);
     }
 
+    @Test
+    public void testTimerStartCron() throws Exception {
+        Application app = ProcessTestHelper.newApplication();
+        NodeLeftCountDownProcessEventListener countDownListener = new 
NodeLeftCountDownProcessEventListener("StartProcess", 3);
+        ProcessTestHelper.registerProcessEventListener(app, countDownListener);
+        final Set<String> startedInstances = new HashSet<>();
+        ProcessTestHelper.registerProcessEventListener(app, new 
DefaultKogitoProcessEventListener() {
+            @Override
+            public void beforeProcessStarted(ProcessStartedEvent event) {
+                startedInstances.add(((KogitoProcessInstance) 
event.getProcessInstance()).getStringId());
+            }
+        });
+        org.kie.kogito.process.Process<TimerStartCronModel> definition = 
TimerStartCronProcess.newProcess(app);
+        assertThat(startedInstances).isEmpty();
+        countDownListener.waitTillCompleted();
+        assertThat(startedInstances).hasSize(3);
+    }
+
     @Test
     public void testTimerStartDuration() throws Exception {
         Application app = ProcessTestHelper.newApplication();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to