This is an automated email from the ASF dual-hosted git repository.
egonzalez 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 c0bbbb1e3f [kie-issues#1965] Support re-scheduling Process Instances
and Node Instances SLA timers (#3940)
c0bbbb1e3f is described below
commit c0bbbb1e3fa40db28717c504e5f773758fe288ec
Author: Pere Fernández <[email protected]>
AuthorDate: Fri May 30 10:21:29 2025 +0200
[kie-issues#1965] Support re-scheduling Process Instances and Node
Instances SLA timers (#3940)
---
.../BaseProcessInstanceManagementResource.java | 26 +++
.../management/ProcessInstanceManagement.java | 4 +
.../kie/kogito/process/management/SlaPayload.java | 41 +++--
.../BaseProcessInstanceManagementResourceTest.java | 10 ++
.../process/event/KogitoProcessEventSupport.java | 5 +-
.../main/java/org/kie/kogito/jobs/JobsService.java | 2 +
.../org/kie/kogito/process/ProcessInstance.java | 5 +
.../uow/events/UnitOfWorkProcessEventListener.java | 23 ++-
.../process/ProcessInstanceNodeEventBody.java | 2 +
.../event/process/ProcessInstanceSLAEventBody.java | 3 +-
.../process/ProcessInstanceStateEventBody.java | 1 +
.../ProcessNodeStateChangeDataEventAdapter.java} | 36 ++---
.../ProcessStateChangeEventDataEventAdapter.java} | 37 ++---
....kie.kogito.event.impl.adapter.DataEventAdapter | 2 +
.../services/jobs/impl/InMemoryJobService.java | 15 +-
.../event/KogitoProcessEventListenerAdapter.java | 20 +--
.../event/KogitoProcessEventSupportImpl.java | 22 +--
.../KogitoProcessNodeStateChangeEventImpl.java | 40 +++++
.../event/ProcessStateChangeEventImpl.java | 40 ++---
.../listeners/RuleAwareProcessEventListener.java | 17 +-
.../workflow/instance/impl/NodeInstanceImpl.java | 5 +
.../instance/impl/WorkflowProcessInstanceImpl.java | 37 +++++
.../workflow/instance/node/EventNodeInstance.java | 18 +++
.../instance/node/StateBasedNodeInstance.java | 19 +++
.../process/impl/AbstractProcessInstance.java | 26 ++-
.../AbstractReactiveMessagingJobsService.java | 6 +
.../jobs/management/quarkus/VertxJobsService.java | 17 ++
.../quarkus/workflows/ProcessManagementIT.java | 39 +++++
.../ProcessInstanceManagementResource.java | 25 ++-
.../src/main/resources/application.properties | 5 +-
.../src/main/resources/timers.bpmn | 178 +++++++++++++++++++++
.../quarkus/ManagementAddOnIT.java | 143 ++++++++++++++++-
.../springboot/SpringRestJobsService.java | 35 ++++
.../ProcessInstanceManagementRestController.java | 20 ++-
.../springboot/ManagementAddOnTest.java | 71 ++++++++
35 files changed, 845 insertions(+), 150 deletions(-)
diff --git
a/addons/common/process-management/src/main/java/org/kie/kogito/process/management/BaseProcessInstanceManagementResource.java
b/addons/common/process-management/src/main/java/org/kie/kogito/process/management/BaseProcessInstanceManagementResource.java
index 5501fc494f..d3dbd70232 100644
---
a/addons/common/process-management/src/main/java/org/kie/kogito/process/management/BaseProcessInstanceManagementResource.java
+++
b/addons/common/process-management/src/main/java/org/kie/kogito/process/management/BaseProcessInstanceManagementResource.java
@@ -321,4 +321,30 @@ public abstract class
BaseProcessInstanceManagementResource<T> implements Proces
protected abstract T badRequestResponse(String message);
protected abstract T notFoundResponse(String message);
+
+ public T doUpdateNodeInstanceSla(String processId, String
processInstanceId, String nodeInstanceId, SlaPayload sla) {
+ return executeOnProcessInstance(processId, processInstanceId,
processInstance -> {
+ try {
+ processInstance.updateNodeInstanceSla(nodeInstanceId,
sla.getExpirationTime());
+ Map<String, Object> message = new HashMap<>();
+ message.put("message", "Node Instance '" + nodeInstanceId + "'
SLA due date successfully updated");
+ return buildOkResponse(message);
+ } catch (Exception e) {
+ return badRequestResponse(e.getMessage());
+ }
+ });
+ }
+
+ public T doUpdateProcessInstanceSla(String processId, String
processInstanceId, SlaPayload sla) {
+ return executeOnProcessInstance(processId, processInstanceId,
processInstance -> {
+ try {
+
processInstance.updateProcessInstanceSla(sla.getExpirationTime());
+ Map<String, Object> message = new HashMap<>();
+ message.put("message", "Process Instance '" +
processInstanceId + "' SLA due date successfully updated");
+ return buildOkResponse(message);
+ } catch (Exception e) {
+ return badRequestResponse(e.getMessage());
+ }
+ });
+ }
}
diff --git
a/addons/common/process-management/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagement.java
b/addons/common/process-management/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagement.java
index 77ae708789..7f877dc9c6 100644
---
a/addons/common/process-management/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagement.java
+++
b/addons/common/process-management/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagement.java
@@ -50,4 +50,8 @@ public interface ProcessInstanceManagement<T> {
T migrateInstance(String processId, String processInstanceId,
ProcessMigrationSpec migrationSpec);
+ T updateNodeInstanceSla(String processId, String processInstanceId, String
nodeInstanceId, SlaPayload SLAPayload);
+
+ T updateProcessInstanceSla(String processId, String processInstanceId,
SlaPayload SLAPayload);
+
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
b/addons/common/process-management/src/main/java/org/kie/kogito/process/management/SlaPayload.java
similarity index 52%
copy from api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
copy to
addons/common/process-management/src/main/java/org/kie/kogito/process/management/SlaPayload.java
index 1271afcc54..92487b3412 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
+++
b/addons/common/process-management/src/main/java/org/kie/kogito/process/management/SlaPayload.java
@@ -16,29 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.kie.kogito.jobs;
-/**
- * JobsService provides an entry point for working with different types of jobs
- * that are meant by default to run in background.
- *
- */
-public interface JobsService {
+package org.kie.kogito.process.management;
+
+import java.time.ZonedDateTime;
+
+public class SlaPayload {
+ private ZonedDateTime expirationTime;
+
+ public SlaPayload() {
+ }
+
+ public SlaPayload(ZonedDateTime expirationTime) {
+ this.expirationTime = expirationTime;
+ }
- /**
- * Schedules process job that is responsible for starting new process
instances
- * based on the given description.
- *
- * @param description defines what kind of process should be started upon
expiration time
- * @return returns unique id of the job
- */
- String scheduleJob(JobDescription description);
+ public ZonedDateTime getExpirationTime() {
+ return expirationTime;
+ }
- /**
- * Cancels given job
- *
- * @param id unique id of the job
- * @return returns true if the cancellation was successful, otherwise false
- */
- boolean cancelJob(String id);
+ public void setExpirationTime(ZonedDateTime expirationTime) {
+ this.expirationTime = expirationTime;
+ }
}
diff --git
a/addons/common/process-management/src/test/java/org/kie/kogito/process/management/BaseProcessInstanceManagementResourceTest.java
b/addons/common/process-management/src/test/java/org/kie/kogito/process/management/BaseProcessInstanceManagementResourceTest.java
index 199d33bd27..d9bdc433a3 100644
---
a/addons/common/process-management/src/test/java/org/kie/kogito/process/management/BaseProcessInstanceManagementResourceTest.java
+++
b/addons/common/process-management/src/test/java/org/kie/kogito/process/management/BaseProcessInstanceManagementResourceTest.java
@@ -221,6 +221,16 @@ class BaseProcessInstanceManagementResourceTest {
public Object migrateInstance(String processId, String
processInstanceId, ProcessMigrationSpec migrationSpec) {
return null;
}
+
+ @Override
+ public Object updateNodeInstanceSla(String processId, String
processInstanceId, String nodeInstanceId, SlaPayload SLAPayload) {
+ return null;
+ }
+
+ @Override
+ public Object updateProcessInstanceSla(String processId, String
processInstanceId, SlaPayload SLAPayload) {
+ return null;
+ }
});
}
diff --git
a/api/kogito-api/src/main/java/org/kie/kogito/internal/process/event/KogitoProcessEventSupport.java
b/api/kogito-api/src/main/java/org/kie/kogito/internal/process/event/KogitoProcessEventSupport.java
index 77565641b0..be913663b8 100644
---
a/api/kogito-api/src/main/java/org/kie/kogito/internal/process/event/KogitoProcessEventSupport.java
+++
b/api/kogito-api/src/main/java/org/kie/kogito/internal/process/event/KogitoProcessEventSupport.java
@@ -38,6 +38,8 @@ public interface KogitoProcessEventSupport {
void fireAfterProcessCompleted(KogitoProcessInstance instance, KieRuntime
kruntime);
+ void fireOnProcessStateChanged(KogitoProcessInstance instance, KieRuntime
kruntime);
+
void fireBeforeNodeTriggered(KogitoNodeInstance nodeInstance, KieRuntime
kruntime);
void fireAfterNodeTriggered(KogitoNodeInstance nodeInstance, KieRuntime
kruntime);
@@ -46,6 +48,8 @@ public interface KogitoProcessEventSupport {
void fireAfterNodeLeft(KogitoNodeInstance nodeInstance, KieRuntime
kruntime);
+ void fireOnNodeStateChanged(KogitoNodeInstance nodeInstance, KieRuntime
kruntime);
+
void fireBeforeVariableChanged(String id, String instanceId, Object
oldValue, Object newValue, List<String> tags,
KogitoProcessInstance processInstance, KogitoNodeInstance
nodeInstance, KieRuntime kruntime);
@@ -77,5 +81,4 @@ public interface KogitoProcessEventSupport {
void addEventListener(KogitoProcessEventListener listener);
void removeEventListener(KogitoProcessEventListener listener);
-
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
b/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
index 1271afcc54..be2b2a033a 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
@@ -41,4 +41,6 @@ public interface JobsService {
* @return returns true if the cancellation was successful, otherwise false
*/
boolean cancelJob(String id);
+
+ String rescheduleJob(JobDescription jobDescription);
}
diff --git
a/api/kogito-api/src/main/java/org/kie/kogito/process/ProcessInstance.java
b/api/kogito-api/src/main/java/org/kie/kogito/process/ProcessInstance.java
index 9c5cad75ed..92229a4968 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/process/ProcessInstance.java
+++ b/api/kogito-api/src/main/java/org/kie/kogito/process/ProcessInstance.java
@@ -18,6 +18,7 @@
*/
package org.kie.kogito.process;
+import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@@ -289,4 +290,8 @@ public interface ProcessInstance<T> {
long version();
Optional<? extends Correlation<?>> correlation();
+
+ void updateNodeInstanceSla(String nodeInstanceId, ZonedDateTime
slaDueDate);
+
+ void updateProcessInstanceSla(ZonedDateTime slaDueDate);
}
diff --git
a/api/kogito-api/src/main/java/org/kie/kogito/uow/events/UnitOfWorkProcessEventListener.java
b/api/kogito-api/src/main/java/org/kie/kogito/uow/events/UnitOfWorkProcessEventListener.java
index ddc09ec964..7d33accfe7 100644
---
a/api/kogito-api/src/main/java/org/kie/kogito/uow/events/UnitOfWorkProcessEventListener.java
+++
b/api/kogito-api/src/main/java/org/kie/kogito/uow/events/UnitOfWorkProcessEventListener.java
@@ -18,18 +18,7 @@
*/
package org.kie.kogito.uow.events;
-import org.kie.api.event.process.ErrorEvent;
-import org.kie.api.event.process.MessageEvent;
-import org.kie.api.event.process.ProcessCompletedEvent;
-import org.kie.api.event.process.ProcessEvent;
-import org.kie.api.event.process.ProcessMigrationEvent;
-import org.kie.api.event.process.ProcessNodeLeftEvent;
-import org.kie.api.event.process.ProcessNodeTriggeredEvent;
-import org.kie.api.event.process.ProcessRetriggeredEvent;
-import org.kie.api.event.process.ProcessStartedEvent;
-import org.kie.api.event.process.ProcessVariableChangedEvent;
-import org.kie.api.event.process.SLAViolatedEvent;
-import org.kie.api.event.process.SignalEvent;
+import org.kie.api.event.process.*;
import org.kie.kogito.internal.process.event.DefaultKogitoProcessEventListener;
import org.kie.kogito.internal.process.event.ProcessWorkItemTransitionEvent;
import org.kie.kogito.uow.UnitOfWorkManager;
@@ -67,6 +56,16 @@ public class UnitOfWorkProcessEventListener extends
DefaultKogitoProcessEventLis
intercept(event);
}
+ @Override
+ public void onProcessStateChanged(ProcessStateChangeEvent event) {
+ intercept(event);
+ }
+
+ @Override
+ public void onNodeStateChanged(ProcessNodeStateChangeEvent event) {
+ intercept(event);
+ }
+
@Override
public void beforeNodeTriggered(ProcessNodeTriggeredEvent event) {
intercept(event);
diff --git
a/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceNodeEventBody.java
b/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceNodeEventBody.java
index a857b94626..fe0b50896e 100644
---
a/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceNodeEventBody.java
+++
b/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceNodeEventBody.java
@@ -53,6 +53,8 @@ public class ProcessInstanceNodeEventBody implements
KogitoMarshallEventSupport,
public static final int EVENT_TYPE_ERROR = 6;
+ public static final int EVENT_TYPE_UPDATED = 7;
+
// common fields for events
private Date eventDate;
diff --git
a/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceSLAEventBody.java
b/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceSLAEventBody.java
index 7801aa094d..1c9d74865e 100644
---
a/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceSLAEventBody.java
+++
b/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceSLAEventBody.java
@@ -133,7 +133,8 @@ public class ProcessInstanceSLAEventBody implements
KogitoMarshallEventSupport,
@Override
public String toString() {
- return "ProcessErrorEventBody [processId=" + processId + ",
processInstanceId=" + processInstanceId + ", nodeDefinitionId=" +
nodeDefinitionId + ", nodeInstanceId=" + nodeInstanceId + "]";
+ return "ProcessInstanceSLAEventBody [processId=" + processId + ",
processInstanceId=" + processInstanceId + ", nodeDefinitionId=" +
nodeDefinitionId + ", nodeInstanceId=" + nodeInstanceId
+ + "]";
}
public static Builder create() {
diff --git
a/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceStateEventBody.java
b/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceStateEventBody.java
index 12e08a56af..aab90cd191 100644
---
a/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceStateEventBody.java
+++
b/api/kogito-events-api/src/main/java/org/kie/kogito/event/process/ProcessInstanceStateEventBody.java
@@ -46,6 +46,7 @@ public class ProcessInstanceStateEventBody implements
KogitoMarshallEventSupport
public static final int EVENT_TYPE_ENDED = 2;
public static final int EVENT_TYPE_MIGRATED = 3;
public static final int EVENT_TYPE_RETRIGGERED = 4;
+ public static final int EVENT_TYPE_UPDATED = 5;
// common fields for events
private Date eventDate;
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
b/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/ProcessNodeStateChangeDataEventAdapter.java
similarity index 52%
copy from api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
copy to
api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/ProcessNodeStateChangeDataEventAdapter.java
index 1271afcc54..21571498b1 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
+++
b/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/ProcessNodeStateChangeDataEventAdapter.java
@@ -16,29 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.kie.kogito.jobs;
-/**
- * JobsService provides an entry point for working with different types of jobs
- * that are meant by default to run in background.
- *
- */
-public interface JobsService {
+package org.kie.kogito.event.impl.adapter;
+
+import org.kie.api.event.process.ProcessNodeStateChangeEvent;
+import org.kie.kogito.event.DataEvent;
+import org.kie.kogito.event.process.ProcessInstanceNodeEventBody;
+
+public class ProcessNodeStateChangeDataEventAdapter extends
AbstractDataEventAdapter {
- /**
- * Schedules process job that is responsible for starting new process
instances
- * based on the given description.
- *
- * @param description defines what kind of process should be started upon
expiration time
- * @return returns unique id of the job
- */
- String scheduleJob(JobDescription description);
+ public ProcessNodeStateChangeDataEventAdapter() {
+ super(ProcessNodeStateChangeEvent.class);
+ }
- /**
- * Cancels given job
- *
- * @param id unique id of the job
- * @return returns true if the cancellation was successful, otherwise false
- */
- boolean cancelJob(String id);
+ @Override
+ public DataEvent<?> adapt(Object payload) {
+ return toProcessInstanceNodeEvent((ProcessNodeStateChangeEvent)
payload, ProcessInstanceNodeEventBody.EVENT_TYPE_UPDATED);
+ }
}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
b/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/ProcessStateChangeEventDataEventAdapter.java
similarity index 51%
copy from api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
copy to
api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/ProcessStateChangeEventDataEventAdapter.java
index 1271afcc54..198ada4dd6 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
+++
b/api/kogito-events-core/src/main/java/org/kie/kogito/event/impl/adapter/ProcessStateChangeEventDataEventAdapter.java
@@ -16,29 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.kie.kogito.jobs;
+package org.kie.kogito.event.impl.adapter;
-/**
- * JobsService provides an entry point for working with different types of jobs
- * that are meant by default to run in background.
- *
- */
-public interface JobsService {
+import org.kie.api.event.process.ProcessStateChangeEvent;
+import org.kie.kogito.event.DataEvent;
+import org.kie.kogito.event.process.ProcessInstanceStateEventBody;
+import org.kie.kogito.internal.process.runtime.KogitoProcessInstance;
+
+public class ProcessStateChangeEventDataEventAdapter extends
AbstractDataEventAdapter {
- /**
- * Schedules process job that is responsible for starting new process
instances
- * based on the given description.
- *
- * @param description defines what kind of process should be started upon
expiration time
- * @return returns unique id of the job
- */
- String scheduleJob(JobDescription description);
+ public ProcessStateChangeEventDataEventAdapter() {
+ super(ProcessStateChangeEvent.class);
+ }
- /**
- * Cancels given job
- *
- * @param id unique id of the job
- * @return returns true if the cancellation was successful, otherwise false
- */
- boolean cancelJob(String id);
+ @Override
+ public DataEvent<?> adapt(Object payload) {
+ ProcessStateChangeEvent event = (ProcessStateChangeEvent) payload;
+ return adapt(event, ProcessInstanceStateEventBody.EVENT_TYPE_UPDATED,
((KogitoProcessInstance) event.getProcessInstance()).getStartDate());
+ }
}
diff --git
a/api/kogito-events-core/src/main/resources/META-INF/services/org.kie.kogito.event.impl.adapter.DataEventAdapter
b/api/kogito-events-core/src/main/resources/META-INF/services/org.kie.kogito.event.impl.adapter.DataEventAdapter
index 06682d2352..62c45d852e 100644
---
a/api/kogito-events-core/src/main/resources/META-INF/services/org.kie.kogito.event.impl.adapter.DataEventAdapter
+++
b/api/kogito-events-core/src/main/resources/META-INF/services/org.kie.kogito.event.impl.adapter.DataEventAdapter
@@ -3,7 +3,9 @@
org.kie.kogito.event.impl.adapter.ProcessErrorEventDataEventAdapter
org.kie.kogito.event.impl.adapter.ProcessMigratedEventDataEventAdapter
org.kie.kogito.event.impl.adapter.ProcessNodeEnteredEventDataEventAdapter
org.kie.kogito.event.impl.adapter.ProcessNodeLeftEventDataEventAdapter
+org.kie.kogito.event.impl.adapter.ProcessNodeStateChangeDataEventAdapter
org.kie.kogito.event.impl.adapter.ProcessSLAEventDataEventAdapter
+org.kie.kogito.event.impl.adapter.ProcessStateChangeEventDataEventAdapter
org.kie.kogito.event.impl.adapter.ProcessStartedEventDataEventAdapter
org.kie.kogito.event.impl.adapter.ProcessRetriggeredEventDataEventAdapter
org.kie.kogito.event.impl.adapter.ProcessVariableEventDataEventAdapter
diff --git
a/api/kogito-services/src/main/java/org/kie/kogito/services/jobs/impl/InMemoryJobService.java
b/api/kogito-services/src/main/java/org/kie/kogito/services/jobs/impl/InMemoryJobService.java
index f48f8b9c2b..fb6fd55e96 100644
---
a/api/kogito-services/src/main/java/org/kie/kogito/services/jobs/impl/InMemoryJobService.java
+++
b/api/kogito-services/src/main/java/org/kie/kogito/services/jobs/impl/InMemoryJobService.java
@@ -24,11 +24,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.*;
import org.kie.kogito.jobs.JobDescription;
import org.kie.kogito.jobs.JobsService;
@@ -110,6 +106,15 @@ public class InMemoryJobService implements JobsService,
AutoCloseable {
return false;
}
+ @Override
+ public String rescheduleJob(JobDescription jobDescription) {
+ LOGGER.debug("Reschedule Job: {}", jobDescription.id());
+ if (cancelJob(jobDescription.id())) {
+ return scheduleJob(jobDescription);
+ }
+ return "Job reschedule failed";
+ }
+
protected long calculateDelay(JobDescription description) {
long delay = Duration.between(ZonedDateTime.now(),
description.expirationTime().get()).toMillis();
if (delay <= 0) {
diff --git
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessEventListenerAdapter.java
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessEventListenerAdapter.java
index 57fd46e93c..9bc6db62b8 100644
---
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessEventListenerAdapter.java
+++
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessEventListenerAdapter.java
@@ -18,15 +18,7 @@
*/
package org.jbpm.process.instance.event;
-import org.kie.api.event.process.MessageEvent;
-import org.kie.api.event.process.ProcessCompletedEvent;
-import org.kie.api.event.process.ProcessEventListener;
-import org.kie.api.event.process.ProcessNodeLeftEvent;
-import org.kie.api.event.process.ProcessNodeTriggeredEvent;
-import org.kie.api.event.process.ProcessStartedEvent;
-import org.kie.api.event.process.ProcessVariableChangedEvent;
-import org.kie.api.event.process.SLAViolatedEvent;
-import org.kie.api.event.process.SignalEvent;
+import org.kie.api.event.process.*;
import org.kie.kogito.internal.process.event.KogitoProcessEventListener;
public class KogitoProcessEventListenerAdapter implements
KogitoProcessEventListener {
@@ -57,6 +49,11 @@ public class KogitoProcessEventListenerAdapter implements
KogitoProcessEventList
delegate.afterProcessCompleted(processCompletedEvent);
}
+ @Override
+ public void onProcessStateChanged(ProcessStateChangeEvent event) {
+ delegate.onProcessStateChanged(event);
+ }
+
@Override
public void beforeNodeTriggered(ProcessNodeTriggeredEvent
processNodeTriggeredEvent) {
delegate.beforeNodeTriggered(processNodeTriggeredEvent);
@@ -77,6 +74,11 @@ public class KogitoProcessEventListenerAdapter implements
KogitoProcessEventList
delegate.afterNodeLeft(processNodeLeftEvent);
}
+ @Override
+ public void onNodeStateChanged(ProcessNodeStateChangeEvent event) {
+ delegate.onNodeStateChanged(event);
+ }
+
@Override
public void beforeVariableChanged(ProcessVariableChangedEvent
processVariableChangedEvent) {
delegate.beforeVariableChanged(processVariableChangedEvent);
diff --git
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessEventSupportImpl.java
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessEventSupportImpl.java
index b03d37b55e..f79a6733c9 100644
---
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessEventSupportImpl.java
+++
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessEventSupportImpl.java
@@ -23,15 +23,7 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
-import org.kie.api.event.process.MessageEvent;
-import org.kie.api.event.process.ProcessCompletedEvent;
-import org.kie.api.event.process.ProcessNodeLeftEvent;
-import org.kie.api.event.process.ProcessNodeTriggeredEvent;
-import org.kie.api.event.process.ProcessRetriggeredEvent;
-import org.kie.api.event.process.ProcessStartedEvent;
-import org.kie.api.event.process.ProcessVariableChangedEvent;
-import org.kie.api.event.process.SLAViolatedEvent;
-import org.kie.api.event.process.SignalEvent;
+import org.kie.api.event.process.*;
import org.kie.api.runtime.KieRuntime;
import org.kie.internal.runtime.Closeable;
import org.kie.kogito.auth.IdentityProvider;
@@ -110,6 +102,12 @@ public class KogitoProcessEventSupportImpl implements
KogitoProcessEventSupport
notifyAllListeners(l -> l.afterProcessCompleted(event));
}
+ @Override
+ public void fireOnProcessStateChanged(KogitoProcessInstance instance,
KieRuntime kruntime) {
+ final ProcessStateChangeEvent event = new
ProcessStateChangeEventImpl(instance, kruntime, identityProvider.getName());
+ notifyAllListeners(l -> l.onProcessStateChanged(event));
+ }
+
@Override
public void fireBeforeNodeTriggered(final KogitoNodeInstance nodeInstance,
KieRuntime kruntime) {
final ProcessNodeTriggeredEvent event = new
KogitoProcessNodeTriggeredEventImpl(nodeInstance, kruntime,
identityProvider.getName());
@@ -134,6 +132,12 @@ public class KogitoProcessEventSupportImpl implements
KogitoProcessEventSupport
notifyAllListeners(l -> l.afterNodeLeft(event));
}
+ @Override
+ public void fireOnNodeStateChanged(KogitoNodeInstance nodeInstance,
KieRuntime kruntime) {
+ final ProcessNodeStateChangeEvent event = new
KogitoProcessNodeStateChangeEventImpl(nodeInstance, kruntime,
identityProvider.getName());
+ notifyAllListeners(l -> l.onNodeStateChanged(event));
+ }
+
@Override
public void fireBeforeVariableChanged(final String id, final String
instanceId,
final Object oldValue, final Object newValue,
diff --git
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessNodeStateChangeEventImpl.java
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessNodeStateChangeEventImpl.java
new file mode 100644
index 0000000000..8f64e3e4dd
--- /dev/null
+++
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/KogitoProcessNodeStateChangeEventImpl.java
@@ -0,0 +1,40 @@
+/*
+ * 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.jbpm.process.instance.event;
+
+import org.kie.api.event.process.ProcessNodeStateChangeEvent;
+import org.kie.api.runtime.KieRuntime;
+import org.kie.api.runtime.process.NodeInstance;
+import org.kie.kogito.internal.process.runtime.KogitoNodeInstance;
+
+public class KogitoProcessNodeStateChangeEventImpl extends
AbstractProcessNodeEvent implements ProcessNodeStateChangeEvent {
+
+ private static final long serialVersionUID = 510l;
+
+ public KogitoProcessNodeStateChangeEventImpl(NodeInstance nodeInstance,
KieRuntime kruntime, String identity) {
+ super(nodeInstance, nodeInstance.getProcessInstance(), kruntime,
identity);
+ }
+
+ @Override
+ public String toString() {
+ return "==>[ProcessNodeStateChangeEvent(nodeId=" +
getNodeInstance().getNodeId() + "; id=" + ((KogitoNodeInstance)
getNodeInstance()).getStringId()
+ + "; nodeName=" + getNodeInstance().getNodeName() + ";
processName=" + getProcessInstance().getProcessName() + "; processId=" +
getProcessInstance().getProcessId() + ")]";
+ }
+}
diff --git a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/ProcessStateChangeEventImpl.java
similarity index 52%
copy from api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
copy to
jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/ProcessStateChangeEventImpl.java
index 1271afcc54..c2c5a72c62 100644
--- a/api/kogito-api/src/main/java/org/kie/kogito/jobs/JobsService.java
+++
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/ProcessStateChangeEventImpl.java
@@ -16,29 +16,23 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.kie.kogito.jobs;
+package org.jbpm.process.instance.event;
-/**
- * JobsService provides an entry point for working with different types of jobs
- * that are meant by default to run in background.
- *
- */
-public interface JobsService {
+import org.kie.api.event.process.ProcessStateChangeEvent;
+import org.kie.api.runtime.KieRuntime;
+import org.kie.api.runtime.process.ProcessInstance;
+
+public class ProcessStateChangeEventImpl extends ProcessEvent implements
ProcessStateChangeEvent {
+
+ private static final long serialVersionUID = 510l;
+
+ public ProcessStateChangeEventImpl(ProcessInstance instance, KieRuntime
kruntime, String identity) {
+ super(instance, kruntime, identity);
+ }
- /**
- * Schedules process job that is responsible for starting new process
instances
- * based on the given description.
- *
- * @param description defines what kind of process should be started upon
expiration time
- * @return returns unique id of the job
- */
- String scheduleJob(JobDescription description);
+ @Override
+ public String toString() {
+ return "==>[ProcessStateChangeEvent(name=" +
getProcessInstance().getProcessName() + "; id=" +
getProcessInstance().getProcessId() + ")]";
+ }
- /**
- * Cancels given job
- *
- * @param id unique id of the job
- * @return returns true if the cancellation was successful, otherwise false
- */
- boolean cancelJob(String id);
-}
+}
\ No newline at end of file
diff --git
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/listeners/RuleAwareProcessEventListener.java
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/listeners/RuleAwareProcessEventListener.java
index 6beee073dd..aaa8d34bf9 100755
---
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/listeners/RuleAwareProcessEventListener.java
+++
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/event/listeners/RuleAwareProcessEventListener.java
@@ -21,12 +21,7 @@ package org.jbpm.process.instance.event.listeners;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
-import org.kie.api.event.process.ProcessCompletedEvent;
-import org.kie.api.event.process.ProcessEventListener;
-import org.kie.api.event.process.ProcessNodeLeftEvent;
-import org.kie.api.event.process.ProcessNodeTriggeredEvent;
-import org.kie.api.event.process.ProcessStartedEvent;
-import org.kie.api.event.process.ProcessVariableChangedEvent;
+import org.kie.api.event.process.*;
import org.kie.api.runtime.KieRuntime;
import org.kie.api.runtime.process.WorkflowProcessInstance;
import org.kie.api.runtime.rule.FactHandle;
@@ -78,6 +73,16 @@ public class RuleAwareProcessEventListener implements
ProcessEventListener {
// do nothing
}
+ @Override
+ public void onProcessStateChanged(ProcessStateChangeEvent event) {
+ // do nothing
+ }
+
+ @Override
+ public void onNodeStateChanged(ProcessNodeStateChangeEvent event) {
+ // do nothing
+ }
+
public void afterNodeLeft(ProcessNodeLeftEvent event) {
// do nothing
}
diff --git
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/NodeInstanceImpl.java
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/NodeInstanceImpl.java
index 90083bf58c..c2bb0054ca 100755
---
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/NodeInstanceImpl.java
+++
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/NodeInstanceImpl.java
@@ -19,6 +19,7 @@
package org.jbpm.workflow.instance.impl;
import java.io.Serializable;
+import java.time.ZonedDateTime;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.Function;
@@ -631,6 +632,10 @@ public abstract class NodeInstanceImpl implements
org.jbpm.workflow.instance.Nod
}
+ public void rescheduleSlaTimer(ZonedDateTime slaDueDate) {
+ throw new UnsupportedOperationException("Unsupported operation");
+ }
+
@Override
public int getSlaCompliance() {
return slaCompliance;
diff --git
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
index 8b1d3614a7..f533f71cbb 100755
---
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
+++
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
@@ -19,6 +19,7 @@
package org.jbpm.workflow.instance.impl;
import java.time.Duration;
+import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -96,6 +97,7 @@ import
org.kie.kogito.internal.process.runtime.KogitoProcessInstance;
import org.kie.kogito.internal.process.runtime.KogitoWorkflowProcess;
import org.kie.kogito.internal.process.runtime.MessageException;
import org.kie.kogito.jobs.DurationExpirationTime;
+import org.kie.kogito.jobs.ExactExpirationTime;
import org.kie.kogito.jobs.JobsService;
import org.kie.kogito.jobs.TimerDescription;
import org.kie.kogito.jobs.descriptors.ProcessInstanceJobDescription;
@@ -113,6 +115,7 @@ import org.mvel2.integration.impl.ImmutableDefaultFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static java.util.Objects.isNull;
import static
org.jbpm.process.core.constants.CalendarConstants.BUSINESS_CALENDAR_ENVIRONMENT_KEY;
import static org.jbpm.ruleflow.core.Metadata.COMPENSATION;
import static org.jbpm.ruleflow.core.Metadata.CONDITION;
@@ -123,6 +126,7 @@ import static
org.jbpm.ruleflow.core.Metadata.EVENT_TYPE_SIGNAL;
import static org.jbpm.ruleflow.core.Metadata.IS_FOR_COMPENSATION;
import static
org.jbpm.workflow.instance.impl.DummyEventListener.EMPTY_EVENT_LISTENER;
import static
org.jbpm.workflow.instance.node.TimerNodeInstance.TIMER_TRIGGERED_EVENT;
+import static org.kie.kogito.internal.utils.ConversionUtils.isEmpty;
import static org.kie.kogito.internal.utils.ConversionUtils.isNotEmpty;
import static org.kie.kogito.process.flexible.ItemDescription.Status.ACTIVE;
import static org.kie.kogito.process.flexible.ItemDescription.Status.AVAILABLE;
@@ -1449,4 +1453,37 @@ public abstract class WorkflowProcessInstanceImpl
extends ProcessInstanceImpl im
return this.kogitoProcessInstance;
}
+ public void rescheduleTimer(String timerId, ZonedDateTime slaDueDate) {
+ rescheduleTimer(timerId, slaDueDate, null);
+ }
+
+ public void rescheduleTimer(String timerId, ZonedDateTime slaDueDate,
String nodeInstanceId) {
+ ProcessInstanceJobDescription description =
+
ProcessInstanceJobDescription.newProcessInstanceJobDescriptionBuilder()
+ .id(timerId)
+ .timerId("-1")
+ .expirationTime(ExactExpirationTime.of(slaDueDate))
+ .processInstanceId(getStringId())
+ .processId(getProcessId())
+ .nodeInstanceId(nodeInstanceId)
+ .rootProcessId(getRootProcessId())
+ .rootProcessInstanceId(getRootProcessInstanceId())
+ .build();
+ JobsService jobsService =
InternalProcessRuntime.asKogitoProcessRuntime(getKnowledgeRuntime().getProcessRuntime()).getJobsService();
+ jobsService.rescheduleJob(description);
+ }
+
+ public void rescheduleSlaTimer(ZonedDateTime slaDueDate) {
+ if (isNull(slaDueDate)) {
+ throw new IllegalArgumentException("Cannot update SLA: slaDueDate
cannot be null");
+ }
+
+ if (isEmpty(slaTimerId)) {
+ throw new IllegalStateException("Cannot update SLA: Process
Instance has NO SLA configured");
+ }
+ InternalProcessRuntime processRuntime = ((InternalProcessRuntime)
getKnowledgeRuntime().getProcessRuntime());
+ rescheduleTimer(slaTimerId, slaDueDate);
+ this.slaDueDate = Date.from(slaDueDate.toInstant());
+
processRuntime.getProcessEventSupport().fireOnProcessStateChanged(this,
getKnowledgeRuntime());
+ }
}
diff --git
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/EventNodeInstance.java
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/EventNodeInstance.java
index 4ad8e4127c..10cc2587e0 100755
---
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/EventNodeInstance.java
+++
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/EventNodeInstance.java
@@ -19,6 +19,7 @@
package org.jbpm.workflow.instance.node;
import java.io.Serializable;
+import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
@@ -42,6 +43,7 @@ import org.kie.kogito.process.EventDescription;
import org.kie.kogito.process.NamedDataType;
import org.kie.kogito.timer.TimerInstance;
+import static java.util.Objects.isNull;
import static
org.jbpm.workflow.instance.impl.DummyEventListener.EMPTY_EVENT_LISTENER;
import static
org.jbpm.workflow.instance.node.TimerNodeInstance.TIMER_TRIGGERED_EVENT;
import static org.kie.kogito.internal.utils.ConversionUtils.isEmpty;
@@ -292,4 +294,20 @@ public class EventNodeInstance extends
ExtendedNodeInstanceImpl implements Kogit
toReturn.add(slaTimer);
return toReturn;
}
+
+ @Override
+ public void rescheduleSlaTimer(ZonedDateTime slaDueDate) {
+ if (isNull(slaDueDate)) {
+ throw new IllegalArgumentException("Cannot update SLA: slaDueDate
cannot be null");
+ }
+
+ if (isEmpty(slaTimerId)) {
+ throw new IllegalStateException("Cannot update SLA: Node has NO
SLA configured");
+ }
+ InternalProcessRuntime processRuntime = ((InternalProcessRuntime)
getProcessInstance().getKnowledgeRuntime().getProcessRuntime());
+ ((WorkflowProcessInstanceImpl)
getProcessInstance()).rescheduleTimer(slaTimerId, slaDueDate, getId());
+ this.slaDueDate = Date.from(slaDueDate.toInstant());
+ processRuntime.getProcessEventSupport().fireOnNodeStateChanged(this,
getProcessInstance().getKnowledgeRuntime());
+ }
+
}
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 2aee1f690e..fab2a6bf67 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
@@ -18,6 +18,7 @@
*/
package org.jbpm.workflow.instance.node;
+import java.time.ZonedDateTime;
import java.util.*;
import org.drools.core.common.InternalAgenda;
@@ -51,9 +52,11 @@ import org.kie.kogito.timer.TimerInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static java.util.Objects.isNull;
import static
org.jbpm.process.core.constants.CalendarConstants.BUSINESS_CALENDAR_ENVIRONMENT_KEY;
import static org.jbpm.workflow.core.Node.CONNECTION_DEFAULT_TYPE;
import static
org.jbpm.workflow.instance.node.TimerNodeInstance.TIMER_TRIGGERED_EVENT;
+import static org.kie.kogito.internal.utils.ConversionUtils.isEmpty;
import static org.kie.kogito.internal.utils.ConversionUtils.isNotEmpty;
public abstract class StateBasedNodeInstance extends ExtendedNodeInstanceImpl
implements EventBasedNodeInstanceInterface, KogitoEventListener {
@@ -494,4 +497,20 @@ public abstract class StateBasedNodeInstance extends
ExtendedNodeInstanceImpl im
return toReturn;
}
+
+ @Override
+ public void rescheduleSlaTimer(ZonedDateTime slaDueDate) {
+ if (isNull(slaDueDate)) {
+ throw new IllegalArgumentException("Cannot update SLA: slaDueDate
cannot be null");
+ }
+
+ if (isEmpty(slaTimerId)) {
+ throw new IllegalStateException("Cannot update SLA: Node has NO
SLA configured");
+ }
+
+ InternalProcessRuntime processRuntime = ((InternalProcessRuntime)
getProcessInstance().getKnowledgeRuntime().getProcessRuntime());
+ ((WorkflowProcessInstanceImpl)
getProcessInstance()).rescheduleTimer(slaTimerId, slaDueDate, getId());
+ this.slaDueDate = Date.from(slaDueDate.toInstant());
+ processRuntime.getProcessEventSupport().fireOnNodeStateChanged(this,
getProcessInstance().getKnowledgeRuntime());
+ }
}
diff --git
a/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcessInstance.java
b/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcessInstance.java
index 73a03b3006..13c9aac1c5 100644
---
a/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcessInstance.java
+++
b/jbpm/jbpm-flow/src/main/java/org/kie/kogito/process/impl/AbstractProcessInstance.java
@@ -19,6 +19,7 @@
package org.kie.kogito.process.impl;
import java.lang.reflect.Field;
+import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -511,7 +512,6 @@ public abstract class AbstractProcessInstance<T extends
Model> implements Proces
.filter(ni -> ni.getStringId().equals(nodeInstanceId))
.findFirst()
.orElseThrow(() -> new
NodeInstanceNotFoundException(this.id, nodeInstanceId));
-
nodeInstance.cancel();
return null;
});
@@ -531,6 +531,27 @@ public abstract class AbstractProcessInstance<T extends
Model> implements Proces
});
}
+ @Override
+ public void updateNodeInstanceSla(String nodeInstanceId, ZonedDateTime
slaDueDate) {
+ executeInWorkflowProcessInstanceWrite(pi -> {
+ NodeInstance nodeInstance = pi.getNodeInstances(true)
+ .stream()
+ .filter(ni -> ni.getId().equals(nodeInstanceId))
+ .findFirst()
+ .orElseThrow(() -> new
NodeInstanceNotFoundException(this.id, nodeInstanceId));
+ ((NodeInstanceImpl) nodeInstance).rescheduleSlaTimer(slaDueDate);
+ return null;
+ });
+ }
+
+ @Override
+ public void updateProcessInstanceSla(ZonedDateTime slaDueDate) {
+ executeInWorkflowProcessInstanceWrite(pi -> {
+ pi.rescheduleSlaTimer(slaDueDate);
+ return null;
+ });
+ }
+
public <R> R
executeInWorkflowProcessInstanceWrite(Function<WorkflowProcessInstanceImpl, R>
execution) {
checkWriteOnly();
return executeInWorkflowProcessInstance(execution);
@@ -545,7 +566,7 @@ public abstract class AbstractProcessInstance<T extends
Model> implements Proces
/**
* this is intended to be used internal. Sometimes is required to perform
low level operations that require some
* internal state of the process like obtaining the SLA or operating nodes
instances.
- *
+ *
* @param <R>
* @param execution
* @return
@@ -667,7 +688,6 @@ public abstract class AbstractProcessInstance<T extends
Model> implements Proces
}
@Override
-
public void transitionWorkItem(String workItemId, WorkItemTransition
transition) {
executeInWorkflowProcessInstanceWrite(pi -> {
getProcessRuntime().getKogitoProcessRuntime().getKogitoWorkItemManager().transitionWorkItem(workItemId,
transition);
diff --git
a/quarkus/addons/jobs/common/messaging/src/main/java/org/kie/kogito/jobs/messaging/quarkus/AbstractReactiveMessagingJobsService.java
b/quarkus/addons/jobs/common/messaging/src/main/java/org/kie/kogito/jobs/messaging/quarkus/AbstractReactiveMessagingJobsService.java
index 3f61e1fe1d..84e2c81ef1 100644
---
a/quarkus/addons/jobs/common/messaging/src/main/java/org/kie/kogito/jobs/messaging/quarkus/AbstractReactiveMessagingJobsService.java
+++
b/quarkus/addons/jobs/common/messaging/src/main/java/org/kie/kogito/jobs/messaging/quarkus/AbstractReactiveMessagingJobsService.java
@@ -94,6 +94,12 @@ public abstract class AbstractReactiveMessagingJobsService
implements JobsServic
return true;
}
+ @Override
+ public String rescheduleJob(JobDescription jobDescription) {
+ cancelJob(jobDescription.id());
+ return scheduleJob(jobDescription);
+ }
+
protected Message<String> decorate(Message<String> message) {
return message;
}
diff --git
a/quarkus/addons/jobs/management/runtime/src/main/java/org/kie/kogito/jobs/management/quarkus/VertxJobsService.java
b/quarkus/addons/jobs/management/runtime/src/main/java/org/kie/kogito/jobs/management/quarkus/VertxJobsService.java
index e5be0229b6..d90a8feedc 100644
---
a/quarkus/addons/jobs/management/runtime/src/main/java/org/kie/kogito/jobs/management/quarkus/VertxJobsService.java
+++
b/quarkus/addons/jobs/management/runtime/src/main/java/org/kie/kogito/jobs/management/quarkus/VertxJobsService.java
@@ -116,6 +116,23 @@ public class VertxJobsService extends RestJobsService {
return true;
}
+ @Override
+ public String rescheduleJob(JobDescription jobDescription) {
+ String callback = getCallbackEndpoint(jobDescription);
+ LOGGER.debug("Job to be rescheduled {} with callback URL {}",
jobDescription, callback);
+ final Job job = buildJob(jobDescription, callback);
+ client.patch(JOBS_PATH).sendJson(job, res -> {
+ int status = res.result() != null ? res.result().statusCode() : 0;
+ if (res.succeeded() && status == 200) {
+ LOGGER.debug("Creating of the job {} done with status code {}
", job, status);
+ System.out.println(res.result().bodyAsString());
+ } else {
+ LOGGER.error("Scheduling of job {} failed with response code
{}", job, status, res.cause());
+ }
+ });
+ return "Job Rescheduled";
+ }
+
private void configureMapper(ObjectMapper mapper) {
mapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
diff --git
a/quarkus/addons/process-management/integration-tests/src/test/java/org/kie/kogito/quarkus/workflows/ProcessManagementIT.java
b/quarkus/addons/process-management/integration-tests/src/test/java/org/kie/kogito/quarkus/workflows/ProcessManagementIT.java
index 9d83bbc17e..21183855ed 100644
---
a/quarkus/addons/process-management/integration-tests/src/test/java/org/kie/kogito/quarkus/workflows/ProcessManagementIT.java
+++
b/quarkus/addons/process-management/integration-tests/src/test/java/org/kie/kogito/quarkus/workflows/ProcessManagementIT.java
@@ -18,9 +18,11 @@
*/
package org.kie.kogito.quarkus.workflows;
+import java.time.ZonedDateTime;
import java.util.Map;
import org.junit.jupiter.api.Test;
+import org.kie.kogito.process.management.SlaPayload;
import io.quarkus.test.junit.QuarkusIntegrationTest;
import io.restassured.RestAssured;
@@ -106,4 +108,41 @@ public class ProcessManagementIT {
hasKey("timerId"),
hasEntry("description", "Task-Boundary Timer"))));
}
+
+ @Test
+ public void testRescheduleSLATimersEndpoints() {
+ String processInstanceId = given()
+ .contentType(ContentType.JSON)
+ .when()
+ .post("/timers")
+ .then()
+ .statusCode(201)
+ .body("id", notNullValue())
+ .extract().path("id");
+
+ String nodeInstanceId = given()
+ .when()
+
.get("/management/processes/timers/instances/{processInstanceId}/nodeInstances",
processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("$.size()", equalTo(1))
+ .extract().path("[0].nodeInstanceId");
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+
.patch("/management/processes/timers/instances/{processInstanceId}/sla",
processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("message", equalTo("Process Instance '" +
processInstanceId + "' SLA due date successfully updated"));
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+ .when()
+
.patch("/management/processes/timers/instances/{processInstanceId}/nodeInstances/{nodeInstanceId}/sla",
processInstanceId, nodeInstanceId)
+ .then()
+ .statusCode(200)
+ .body("message", equalTo("Node Instance '" + nodeInstanceId +
"' SLA due date successfully updated"));
+ }
}
diff --git
a/quarkus/addons/process-management/runtime/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagementResource.java
b/quarkus/addons/process-management/runtime/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagementResource.java
index 6bf8433f63..9aecfa2ecb 100644
---
a/quarkus/addons/process-management/runtime/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagementResource.java
+++
b/quarkus/addons/process-management/runtime/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagementResource.java
@@ -23,12 +23,7 @@ import org.kie.kogito.process.Processes;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@@ -189,4 +184,22 @@ public class ProcessInstanceManagementResource extends
BaseProcessInstanceManage
public Response cancelProcessInstanceId(@PathParam("processId") String
processId, @PathParam("processInstanceId") String processInstanceId) {
return doCancelProcessInstanceId(processId, processInstanceId);
}
+
+ @Override
+ @PATCH
+
@Path("{processId}/instances/{processInstanceId}/nodeInstances/{nodeInstanceId}/sla")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updateNodeInstanceSla(@PathParam("processId") String
processId, @PathParam("processInstanceId") String processInstanceId,
@PathParam("nodeInstanceId") String nodeInstanceId,
+ SlaPayload slaPayload) {
+ return doUpdateNodeInstanceSla(processId, processInstanceId,
nodeInstanceId, slaPayload);
+ }
+
+ @Override
+ @PATCH
+ @Path("{processId}/instances/{processInstanceId}/sla")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response updateProcessInstanceSla(@PathParam("processId") String
processId, @PathParam("processInstanceId") String processInstanceId, SlaPayload
slaPayload) {
+ return doUpdateProcessInstanceSla(processId, processInstanceId,
slaPayload);
+ }
+
}
diff --git
a/quarkus/integration-tests/integration-tests-quarkus-processes/src/main/resources/application.properties
b/quarkus/integration-tests/integration-tests-quarkus-processes/src/main/resources/application.properties
index 58d7ff6dc2..b3eaaa789f 100644
---
a/quarkus/integration-tests/integration-tests-quarkus-processes/src/main/resources/application.properties
+++
b/quarkus/integration-tests/integration-tests-quarkus-processes/src/main/resources/application.properties
@@ -53,4 +53,7 @@ quarkus.http.auth.permission.default.policy=authenticated
quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
-quarkus.security.users.embedded.users.buddy=buddy
\ No newline at end of file
+quarkus.security.users.embedded.users.buddy=buddy
+
+kogito.transactionEnabled=false
+kogito.faultToleranceEnabled=false
\ No newline at end of file
diff --git
a/quarkus/integration-tests/integration-tests-quarkus-processes/src/main/resources/timers.bpmn
b/quarkus/integration-tests/integration-tests-quarkus-processes/src/main/resources/timers.bpmn
new file mode 100644
index 0000000000..63b3bac089
--- /dev/null
+++
b/quarkus/integration-tests/integration-tests-quarkus-processes/src/main/resources/timers.bpmn
@@ -0,0 +1,178 @@
+<?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: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="_FbQn4Bn5ED6qPL2RHaehww"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd
http://www. [...]
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_SkippableInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_PriorityInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_CommentInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_DescriptionInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_CreatedByInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_TaskNameInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_GroupIdInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_ContentInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_NotStartedReassignInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_NotCompletedReassignInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_NotStartedNotifyInputXItem"
structureRef="Object"/>
+ <bpmn2:itemDefinition
id="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_NotCompletedNotifyInputXItem"
structureRef="Object"/>
+ <bpmn2:collaboration id="_11F36E9B-11DF-499D-896C-0D73277FBCB5"
name="Default Collaboration">
+ <bpmn2:participant id="_3CC3D518-96F1-4246-B77A-BD69EA62333A" name="Pool
Participant" processRef="timers"/>
+ </bpmn2:collaboration>
+ <bpmn2:process id="timers" drools:packageName="com.example"
drools:version="1.0" drools:adHoc="false" name="timers" isExecutable="true"
processType="Public">
+ <bpmn2:extensionElements>
+ <drools:metaData name="customSLADueDate">
+ <drools:metaValue><![CDATA[200m]]></drools:metaValue>
+ </drools:metaData>
+ <drools:metaData name="processDuration">
+ <drools:metaValue><![CDATA[PT1M]]></drools:metaValue>
+ </drools:metaData>
+ </bpmn2:extensionElements>
+ <bpmn2:sequenceFlow id="_2CCE6D96-07C9-4196-A3DA-2FA12675606B"
sourceRef="_C64FDE83-9AE3-4BC8-94AC-14805BE0D3D3"
targetRef="_A2B595B9-3809-487E-B354-677DE3EB9B83"/>
+ <bpmn2:sequenceFlow id="_217C7B88-D29D-479F-9DDA-49C505B55DB3"
sourceRef="_CB75879B-EB0D-4F28-AC61-E6FAA0126490"
targetRef="_66215F0B-D52C-4DEF-8BAE-3524FD59A246"/>
+ <bpmn2:sequenceFlow id="_BB186F29-4721-4C71-BFAA-D816C47ED670"
sourceRef="_F35EC805-22D5-4833-B56D-9DE16B4B258B"
targetRef="_CB75879B-EB0D-4F28-AC61-E6FAA0126490"/>
+ <bpmn2:endEvent id="_A2B595B9-3809-487E-B354-677DE3EB9B83">
+ <bpmn2:incoming>_2CCE6D96-07C9-4196-A3DA-2FA12675606B</bpmn2:incoming>
+ </bpmn2:endEvent>
+ <bpmn2:endEvent id="_66215F0B-D52C-4DEF-8BAE-3524FD59A246">
+ <bpmn2:incoming>_217C7B88-D29D-479F-9DDA-49C505B55DB3</bpmn2:incoming>
+ </bpmn2:endEvent>
+ <bpmn2:userTask id="_CB75879B-EB0D-4F28-AC61-E6FAA0126490" name="Task">
+ <bpmn2:extensionElements>
+ <drools:metaData name="elementname">
+ <drools:metaValue><![CDATA[Task]]></drools:metaValue>
+ </drools:metaData>
+ <drools:metaData name="customSLADueDate">
+ <drools:metaValue><![CDATA[150m]]></drools:metaValue>
+ </drools:metaData>
+ </bpmn2:extensionElements>
+ <bpmn2:incoming>_BB186F29-4721-4C71-BFAA-D816C47ED670</bpmn2:incoming>
+ <bpmn2:outgoing>_217C7B88-D29D-479F-9DDA-49C505B55DB3</bpmn2:outgoing>
+ <bpmn2:ioSpecification>
+ <bpmn2:dataInput
id="_CB75879B-EB0D-4F28-AC61-E6FAA0126490_TaskNameInputX" drools:dtype="Object"
itemSubjectRef="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_TaskNameInputXItem"
name="TaskName"/>
+ <bpmn2:dataInput
id="_CB75879B-EB0D-4F28-AC61-E6FAA0126490_SkippableInputX"
drools:dtype="Object"
itemSubjectRef="__CB75879B-EB0D-4F28-AC61-E6FAA0126490_SkippableInputXItem"
name="Skippable"/>
+ <bpmn2:inputSet>
+
<bpmn2:dataInputRefs>_CB75879B-EB0D-4F28-AC61-E6FAA0126490_TaskNameInputX</bpmn2:dataInputRefs>
+
<bpmn2:dataInputRefs>_CB75879B-EB0D-4F28-AC61-E6FAA0126490_SkippableInputX</bpmn2:dataInputRefs>
+ </bpmn2:inputSet>
+ </bpmn2:ioSpecification>
+ <bpmn2:dataInputAssociation>
+
<bpmn2:targetRef>_CB75879B-EB0D-4F28-AC61-E6FAA0126490_TaskNameInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from
xsi:type="bpmn2:tFormalExpression"><![CDATA[Task]]></bpmn2:from>
+ <bpmn2:to
xsi:type="bpmn2:tFormalExpression"><![CDATA[_CB75879B-EB0D-4F28-AC61-E6FAA0126490_TaskNameInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:dataInputAssociation>
+
<bpmn2:targetRef>_CB75879B-EB0D-4F28-AC61-E6FAA0126490_SkippableInputX</bpmn2:targetRef>
+ <bpmn2:assignment>
+ <bpmn2:from
xsi:type="bpmn2:tFormalExpression"><![CDATA[false]]></bpmn2:from>
+ <bpmn2:to
xsi:type="bpmn2:tFormalExpression"><![CDATA[_CB75879B-EB0D-4F28-AC61-E6FAA0126490_SkippableInputX]]></bpmn2:to>
+ </bpmn2:assignment>
+ </bpmn2:dataInputAssociation>
+ <bpmn2:potentialOwner id="_FbR2ABn5ED6qPL2RHaehww">
+ <bpmn2:resourceAssignmentExpression id="_FbR2ARn5ED6qPL2RHaehww">
+ <bpmn2:formalExpression>jdoe</bpmn2:formalExpression>
+ </bpmn2:resourceAssignmentExpression>
+ </bpmn2:potentialOwner>
+ </bpmn2:userTask>
+ <bpmn2:startEvent id="_F35EC805-22D5-4833-B56D-9DE16B4B258B">
+ <bpmn2:outgoing>_BB186F29-4721-4C71-BFAA-D816C47ED670</bpmn2:outgoing>
+ </bpmn2:startEvent>
+ <bpmn2:boundaryEvent id="_C64FDE83-9AE3-4BC8-94AC-14805BE0D3D3"
drools:dockerinfo="70.42^74|" drools:boundaryca="true" name="Boundary Timer"
attachedToRef="_CB75879B-EB0D-4F28-AC61-E6FAA0126490">
+ <bpmn2:extensionElements>
+ <drools:metaData name="elementname">
+ <drools:metaValue><![CDATA[Boundary Timer]]></drools:metaValue>
+ </drools:metaData>
+ </bpmn2:extensionElements>
+ <bpmn2:outgoing>_2CCE6D96-07C9-4196-A3DA-2FA12675606B</bpmn2:outgoing>
+ <bpmn2:timerEventDefinition>
+ <bpmn2:timeDuration
xsi:type="bpmn2:tFormalExpression">PT180S</bpmn2:timeDuration>
+ </bpmn2:timerEventDefinition>
+ </bpmn2:boundaryEvent>
+ </bpmn2:process>
+ <bpmndi:BPMNDiagram>
+ <bpmndi:BPMNPlane bpmnElement="timers">
+ <bpmndi:BPMNShape id="shape__F35EC805-22D5-4833-B56D-9DE16B4B258B"
bpmnElement="_F35EC805-22D5-4833-B56D-9DE16B4B258B">
+ <dc:Bounds height="56" width="56" x="325" y="97"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__CB75879B-EB0D-4F28-AC61-E6FAA0126490"
bpmnElement="_CB75879B-EB0D-4F28-AC61-E6FAA0126490">
+ <dc:Bounds height="102" width="154" x="448" y="74"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__66215F0B-D52C-4DEF-8BAE-3524FD59A246"
bpmnElement="_66215F0B-D52C-4DEF-8BAE-3524FD59A246">
+ <dc:Bounds height="56" width="56" x="682" y="97"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__C64FDE83-9AE3-4BC8-94AC-14805BE0D3D3"
bpmnElement="_C64FDE83-9AE3-4BC8-94AC-14805BE0D3D3">
+ <dc:Bounds height="56" width="56" x="518.42" y="148"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="shape__A2B595B9-3809-487E-B354-677DE3EB9B83"
bpmnElement="_A2B595B9-3809-487E-B354-677DE3EB9B83">
+ <dc:Bounds height="56" width="56" x="682" y="246"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNEdge
id="edge_shape__F35EC805-22D5-4833-B56D-9DE16B4B258B_to_shape__CB75879B-EB0D-4F28-AC61-E6FAA0126490"
bpmnElement="_BB186F29-4721-4C71-BFAA-D816C47ED670">
+ <di:waypoint x="353" y="125"/>
+ <di:waypoint x="525" y="125"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge
id="edge_shape__CB75879B-EB0D-4F28-AC61-E6FAA0126490_to_shape__66215F0B-D52C-4DEF-8BAE-3524FD59A246"
bpmnElement="_217C7B88-D29D-479F-9DDA-49C505B55DB3">
+ <di:waypoint x="525" y="125"/>
+ <di:waypoint x="710" y="125"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge
id="edge_shape__C64FDE83-9AE3-4BC8-94AC-14805BE0D3D3_to_shape__A2B595B9-3809-487E-B354-677DE3EB9B83"
bpmnElement="_2CCE6D96-07C9-4196-A3DA-2FA12675606B">
+ <di:waypoint x="546.42" y="176"/>
+ <di:waypoint x="546.42" y="274"/>
+ <di:waypoint x="682" y="274"/>
+ </bpmndi:BPMNEdge>
+ </bpmndi:BPMNPlane>
+ </bpmndi:BPMNDiagram>
+ <bpmn2:relationship type="BPSimData">
+ <bpmn2:extensionElements>
+ <bpsim:BPSimData>
+ <bpsim:Scenario id="default" name="Simulationscenario">
+ <bpsim:ScenarioParameters/>
+ <bpsim:ElementParameters
elementRef="_F35EC805-22D5-4833-B56D-9DE16B4B258B">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ </bpsim:ElementParameters>
+ <bpsim:ElementParameters
elementRef="_CB75879B-EB0D-4F28-AC61-E6FAA0126490">
+ <bpsim:TimeParameters>
+ <bpsim:ProcessingTime>
+ <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+ </bpsim:ProcessingTime>
+ </bpsim:TimeParameters>
+ <bpsim:ResourceParameters>
+ <bpsim:Availability>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Availability>
+ <bpsim:Quantity>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:Quantity>
+ </bpsim:ResourceParameters>
+ <bpsim:CostParameters>
+ <bpsim:UnitCost>
+ <bpsim:FloatingParameter value="0"/>
+ </bpsim:UnitCost>
+ </bpsim:CostParameters>
+ </bpsim:ElementParameters>
+ </bpsim:Scenario>
+ </bpsim:BPSimData>
+ </bpmn2:extensionElements>
+ <bpmn2:source>_FbQn4Bn5ED6qPL2RHaehww</bpmn2:source>
+ <bpmn2:target>_FbQn4Bn5ED6qPL2RHaehww</bpmn2:target>
+ </bpmn2:relationship>
+</bpmn2:definitions>
\ No newline at end of file
diff --git
a/quarkus/integration-tests/integration-tests-quarkus-processes/src/test/java/org/kie/kogito/integrationtests/quarkus/ManagementAddOnIT.java
b/quarkus/integration-tests/integration-tests-quarkus-processes/src/test/java/org/kie/kogito/integrationtests/quarkus/ManagementAddOnIT.java
index 95500eb16a..bb38bcca52 100644
---
a/quarkus/integration-tests/integration-tests-quarkus-processes/src/test/java/org/kie/kogito/integrationtests/quarkus/ManagementAddOnIT.java
+++
b/quarkus/integration-tests/integration-tests-quarkus-processes/src/test/java/org/kie/kogito/integrationtests/quarkus/ManagementAddOnIT.java
@@ -18,9 +18,12 @@
*/
package org.kie.kogito.integrationtests.quarkus;
+import java.time.ZonedDateTime;
import java.util.List;
+import java.util.Map;
import org.junit.jupiter.api.Test;
+import org.kie.kogito.process.management.SlaPayload;
import io.quarkus.test.junit.QuarkusIntegrationTest;
import io.restassured.RestAssured;
@@ -32,14 +35,14 @@ import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.Matchers.emptyOrNullString;
-import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.*;
@QuarkusIntegrationTest
class ManagementAddOnIT {
private static final String HELLO1_NODE =
"_3CDC6E61-DCC5-4831-8BBB-417CFF517CB0";
private static final String GREETINGS = "greetings";
+ private static final String TIMERS = "timers";
static {
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
@@ -151,4 +154,140 @@ class ManagementAddOnIT {
.statusCode(200)
.extract().response().jsonPath().getList("nodeInstanceId");
}
+
+ @Test
+ void testManagementTimersEndpoint() {
+ String processInstanceId = given()
+ .body(Map.of())
+ .contentType(ContentType.JSON)
+ .when()
+ .post("/{processId}", TIMERS)
+ .then()
+ .statusCode(201)
+ .body("id", notNullValue())
+ .extract().path("id");
+
+ String nodeInstanceId = given()
+ .when()
+
.get("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances",
TIMERS, processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("$.size()", equalTo(1))
+ .extract().path("[0].nodeInstanceId");
+
+ given()
+ .when()
+
.get("/management/processes/{processId}/instances/{processInstanceId}/timers",
TIMERS, processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("$.size()", equalTo(4))
+ .body("", hasItem(allOf(
+ hasEntry("processId", "timers"),
+ hasEntry("processInstanceId", processInstanceId),
+ hasKey("timerId"),
+ hasEntry("description", "[SLA-Process] timers"))))
+ .body("", hasItem(allOf(
+ hasEntry("processId", "timers"),
+ hasEntry("processInstanceId", processInstanceId),
+ hasKey("timerId"),
+ hasEntry("description", "[CANCEL-Process] timers"))))
+ .body("", hasItem(allOf(
+ hasEntry("processId", "timers"),
+ hasEntry("processInstanceId", processInstanceId),
+ hasEntry("nodeInstanceId", nodeInstanceId),
+ hasKey("timerId"),
+ hasEntry("description", "[SLA] Task"))))
+ .body("", hasItem(allOf(
+ hasEntry("processId", "timers"),
+ hasEntry("processInstanceId", processInstanceId),
+ hasEntry("nodeInstanceId", nodeInstanceId),
+ hasKey("timerId"),
+ hasEntry("description", "Task-Boundary Timer"))));
+
+ given()
+ .when()
+
.get("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances/{nodeInstanceId}/timers",
TIMERS, processInstanceId, nodeInstanceId)
+ .then()
+ .statusCode(200)
+ .body("$.size()", equalTo(2))
+ .body("", hasItem(allOf(
+ hasEntry("processId", "timers"),
+ hasEntry("processInstanceId", processInstanceId),
+ hasEntry("nodeInstanceId", nodeInstanceId),
+ hasKey("timerId"),
+ hasEntry("description", "[SLA] Task"))))
+ .body("", hasItem(allOf(
+ hasEntry("processId", "timers"),
+ hasEntry("processInstanceId", processInstanceId),
+ hasEntry("nodeInstanceId", nodeInstanceId),
+ hasKey("timerId"),
+ hasEntry("description", "Task-Boundary Timer"))));
+ }
+
+ @Test
+ public void testRescheduleSLATimersEndpoints() {
+ String processInstanceId = given()
+ .contentType(ContentType.JSON)
+ .when()
+ .post("/{processId}", TIMERS)
+ .then()
+ .statusCode(201)
+ .body("id", notNullValue())
+ .extract().path("id");
+
+ String nodeInstanceId = given()
+ .when()
+
.get("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances",
TIMERS, processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("$.size()", equalTo(1))
+ .extract().path("[0].nodeInstanceId");
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+
.patch("/management/processes/{processId}/instances/{processInstanceId}/sla",
TIMERS, processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("message", equalTo("Process Instance '" +
processInstanceId + "' SLA due date successfully updated"));
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+ .when()
+
.patch("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances/{nodeInstanceId}/sla",
TIMERS, processInstanceId, nodeInstanceId)
+ .then()
+ .statusCode(200)
+ .body("message", equalTo("Node Instance '" + nodeInstanceId +
"' SLA due date successfully updated"));
+ }
+
+ @Test
+ public void testRescheduleSLATimersProcessInstanceWithoutSLAsConfigured() {
+ String processInstanceId = givenGreetingsProcess();
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+
.patch("/management/processes/{processId}/instances/{processInstanceId}/sla",
GREETINGS, processInstanceId)
+ .then()
+ .statusCode(400)
+ .body(equalTo("Cannot update SLA: Process Instance has NO SLA
configured"));
+
+ String nodeInstanceId = given()
+ .when()
+
.get("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances",
GREETINGS, processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("$.size()", equalTo(2))
+ .extract().path("[0].nodeInstanceId");
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+ .when()
+
.patch("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances/{nodeInstanceId}/sla",
GREETINGS, processInstanceId, nodeInstanceId)
+ .then()
+ .statusCode(400)
+ .body(equalTo("Cannot update SLA: Node has NO SLA
configured"));
+ }
}
diff --git
a/springboot/addons/jobs/src/main/java/org/kie/kogito/jobs/management/springboot/SpringRestJobsService.java
b/springboot/addons/jobs/src/main/java/org/kie/kogito/jobs/management/springboot/SpringRestJobsService.java
index b89392c51e..6549825538 100644
---
a/springboot/addons/jobs/src/main/java/org/kie/kogito/jobs/management/springboot/SpringRestJobsService.java
+++
b/springboot/addons/jobs/src/main/java/org/kie/kogito/jobs/management/springboot/SpringRestJobsService.java
@@ -18,6 +18,9 @@
*/
package org.kie.kogito.jobs.management.springboot;
+import java.util.HashMap;
+import java.util.Map;
+
import org.kie.kogito.jobs.JobDescription;
import org.kie.kogito.jobs.management.RestJobsService;
import org.kie.kogito.jobs.service.api.Job;
@@ -27,6 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -99,6 +103,23 @@ public class SpringRestJobsService extends RestJobsService {
}
}
+ @Override
+ public String rescheduleJob(JobDescription jobDescription) {
+ String callback = getCallbackEndpoint(jobDescription);
+ LOGGER.debug("Job to be rescheduled {} with callback URL {}",
jobDescription, callback);
+ final Job job = buildJob(jobDescription, callback);
+ final HttpEntity<String> request = buildJobRequest(job);
+ ResponseEntity<String> response = restTemplate.exchange(
+ getJobsServiceUri(),
+ HttpMethod.PATCH,
+ request,
+ String.class);
+ if
(response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(200))) {
+ LOGGER.debug("Rescheduling of the job {} done with status code {}
", job, response.getStatusCode());
+ }
+ return "Job Rescheduled";
+ }
+
private HttpEntity<String> buildJobRequest(Job job) {
String json;
try {
@@ -110,4 +131,18 @@ public class SpringRestJobsService extends RestJobsService
{
headers.setContentType(MediaType.APPLICATION_JSON);
return new HttpEntity<>(json, headers);
}
+
+ private HttpEntity<String> buildJobRequest(String id) {
+ String json;
+ try {
+ Map<String, String> job = new HashMap<>();
+ job.put("id", id);
+ json = objectMapper.writeValueAsString(job);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("It was not possible to create the http
request for the job id: " + id, e);
+ }
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ return new HttpEntity<>(json, headers);
+ }
}
diff --git
a/springboot/addons/process-management/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagementRestController.java
b/springboot/addons/process-management/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagementRestController.java
index eec6482af3..55c646b78a 100644
---
a/springboot/addons/process-management/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagementRestController.java
+++
b/springboot/addons/process-management/src/main/java/org/kie/kogito/process/management/ProcessInstanceManagementRestController.java
@@ -24,12 +24,7 @@ import
org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@@ -152,4 +147,17 @@ public class ProcessInstanceManagementRestController
extends BaseProcessInstance
return doCancelProcessInstanceId(processId, processInstanceId);
}
+ @Override
+ @PatchMapping(value =
"{processId}/instances/{processInstanceId}/nodeInstances/{nodeInstanceId}/sla")
+ public ResponseEntity updateNodeInstanceSla(@PathVariable("processId")
String processId, @PathVariable("processInstanceId") String processInstanceId,
+ @PathVariable("nodeInstanceId") String nodeInstanceId,
@RequestBody SlaPayload slaPayload) {
+ return doUpdateNodeInstanceSla(processId, processInstanceId,
nodeInstanceId, slaPayload);
+ }
+
+ @Override
+ @PatchMapping(value = "{processId}/instances/{processInstanceId}/sla")
+ public ResponseEntity updateProcessInstanceSla(@PathVariable("processId")
String processId, @PathVariable("processInstanceId") String processInstanceId,
@RequestBody SlaPayload slaPayload) {
+ return doUpdateProcessInstanceSla(processId, processInstanceId,
slaPayload);
+ }
+
}
diff --git
a/springboot/integration-tests/integration-tests-springboot-processes-it/src/test/java/org/kie/kogito/integrationtests/springboot/ManagementAddOnTest.java
b/springboot/integration-tests/integration-tests-springboot-processes-it/src/test/java/org/kie/kogito/integrationtests/springboot/ManagementAddOnTest.java
index d15ee2104c..d8e7b94fd1 100644
---
a/springboot/integration-tests/integration-tests-springboot-processes-it/src/test/java/org/kie/kogito/integrationtests/springboot/ManagementAddOnTest.java
+++
b/springboot/integration-tests/integration-tests-springboot-processes-it/src/test/java/org/kie/kogito/integrationtests/springboot/ManagementAddOnTest.java
@@ -18,12 +18,14 @@
*/
package org.kie.kogito.integrationtests.springboot;
+import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.kie.kogito.process.management.SlaPayload;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -38,6 +40,7 @@ import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.*;
@ExtendWith(SpringExtension.class)
@@ -200,6 +203,74 @@ class ManagementAddOnTest extends BaseRestTest {
hasEntry("description", "Task-Boundary Timer"))));
}
+ @Test
+ public void testRescheduleSLATimersEndpoints() {
+ String processInstanceId = given()
+ .body(Map.of())
+ .contentType(ContentType.JSON)
+ .when()
+ .post("/timers")
+ .then()
+ .statusCode(201)
+ .body("id", notNullValue())
+ .extract().path("id");
+
+ String nodeInstanceId = given()
+ .when()
+
.get("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances",
TIMERS, processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("$.size()", equalTo(1))
+ .extract().path("[0].nodeInstanceId");
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+
.patch("/management/processes/{processId}/instances/{processInstanceId}/sla",
TIMERS, processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("message", equalTo("Process Instance '" +
processInstanceId + "' SLA due date successfully updated"));
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+ .when()
+
.patch("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances/{nodeInstanceId}/sla",
TIMERS, processInstanceId, nodeInstanceId)
+ .then()
+ .statusCode(200)
+ .body("message", equalTo("Node Instance '" + nodeInstanceId +
"' SLA due date successfully updated"));
+ }
+
+ @Test
+ public void testRescheduleSLATimersProcessInstanceWithoutSLAsConfigured() {
+ String processInstanceId = givenGreetingsProcess();
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+
.patch("/management/processes/{processId}/instances/{processInstanceId}/sla",
GREETINGS, processInstanceId)
+ .then()
+ .statusCode(400)
+ .body(equalTo("Cannot update SLA: Process Instance has NO SLA
configured"));
+
+ String nodeInstanceId = given()
+ .when()
+
.get("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances",
GREETINGS, processInstanceId)
+ .then()
+ .statusCode(200)
+ .body("$.size()", equalTo(2))
+ .extract().path("[0].nodeInstanceId");
+
+ given()
+ .body(new SlaPayload(ZonedDateTime.now()))
+ .contentType(ContentType.JSON)
+ .when()
+
.patch("/management/processes/{processId}/instances/{processInstanceId}/nodeInstances/{nodeInstanceId}/sla",
GREETINGS, processInstanceId, nodeInstanceId)
+ .then()
+ .statusCode(400)
+ .body(equalTo("Cannot update SLA: Node has NO SLA
configured"));
+ }
+
private String givenGreetingsProcess() {
return given().contentType(ContentType.JSON)
.when()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]