Skip to content

Commit

Permalink
[KOGITO-9811] Resolving timer on runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
fjtirado committed Oct 31, 2023
1 parent 7f148ed commit b73b03c
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@
import org.jbpm.process.core.timer.Timer;
import org.jbpm.process.instance.InternalProcessRuntime;
import org.jbpm.process.instance.impl.Action;
import org.jbpm.ruleflow.core.Metadata;
import org.jbpm.util.ContextFactory;
import org.jbpm.workflow.core.DroolsAction;
import org.jbpm.workflow.core.WorkflowProcess;
import org.jbpm.workflow.core.impl.NodeImpl;
import org.jbpm.workflow.core.node.StateBasedNode;
import org.jbpm.workflow.instance.impl.ExtendedNodeInstanceImpl;
import org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl;
Expand All @@ -51,6 +54,8 @@
import org.kie.kogito.jobs.ExpirationTime;
import org.kie.kogito.jobs.JobsService;
import org.kie.kogito.jobs.ProcessInstanceJobDescription;
import org.kie.kogito.process.expr.Expression;
import org.kie.kogito.process.expr.ExpressionHandlerFactory;
import org.kie.kogito.timer.TimerInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -68,6 +73,8 @@ public abstract class StateBasedNodeInstance extends ExtendedNodeInstanceImpl im

private Map<String, String> timerInstancesReference;

private transient KogitoProcessContext context;

public StateBasedNode getEventBasedNode() {
return (StateBasedNode) getNode();
}
Expand Down Expand Up @@ -144,8 +151,8 @@ protected ExpirationTime createTimerInstance(Timer timer) {
switch (timer.getTimeType()) {
case Timer.TIME_CYCLE:

String tempDelay = resolveExpression(timer.getDelay());
String tempPeriod = resolveExpression(timer.getPeriod());
String tempDelay = resolveTimerExpression(timer.getDelay());
String tempPeriod = resolveTimerExpression(timer.getPeriod());
if (DateTimeUtils.isRepeatable(tempDelay)) {
String[] values = DateTimeUtils.parseISORepeatable(tempDelay);
String tempRepeatLimit = values[0];
Expand Down Expand Up @@ -174,7 +181,7 @@ protected ExpirationTime createTimerInstance(Timer timer) {
}

case Timer.TIME_DURATION:
delay = resolveExpression(timer.getDelay());
delay = resolveTimerExpression(timer.getDelay());

return DurationExpirationTime.repeat(businessCalendar.calculateBusinessTimeAsDuration(delay));
case Timer.TIME_DATE:
Expand All @@ -196,14 +203,14 @@ protected ExpirationTime configureTimerInstance(Timer timer) {
case Timer.TIME_CYCLE:
if (timer.getPeriod() != null) {

long actualDelay = DateTimeUtils.parseDuration(resolveExpression(timer.getDelay()));
long actualDelay = DateTimeUtils.parseDuration(resolveTimerExpression(timer.getDelay()));
if (timer.getPeriod() == null) {
return DurationExpirationTime.repeat(actualDelay, actualDelay, Integer.MAX_VALUE);
} else {
return DurationExpirationTime.repeat(actualDelay, DateTimeUtils.parseDuration(resolveExpression(timer.getPeriod())), Integer.MAX_VALUE);
return DurationExpirationTime.repeat(actualDelay, DateTimeUtils.parseDuration(resolveTimerExpression(timer.getPeriod())), Integer.MAX_VALUE);
}
} else {
String resolvedDelay = resolveExpression(timer.getDelay());
String resolvedDelay = resolveTimerExpression(timer.getDelay());

// when using ISO date/time period is not set
long[] repeatValues = null;
Expand Down Expand Up @@ -233,7 +240,7 @@ protected ExpirationTime configureTimerInstance(Timer timer) {
duration = DateTimeUtils.parseDuration(timer.getDelay());
} catch (RuntimeException e) {
// cannot parse delay, trying to interpret it
s = resolveExpression(timer.getDelay());
s = resolveTimerExpression(timer.getDelay());
duration = DateTimeUtils.parseDuration(s);
}
return DurationExpirationTime.after(duration);
Expand All @@ -243,13 +250,29 @@ protected ExpirationTime configureTimerInstance(Timer timer) {
return ExactExpirationTime.of(timer.getDate());
} catch (RuntimeException e) {
// cannot parse delay, trying to interpret it
s = resolveExpression(timer.getDate());
s = resolveTimerExpression(timer.getDate());
return ExactExpirationTime.of(s);
}
}
throw new UnsupportedOperationException("Not supported timer definition");
}

private String resolveTimerExpression(String expression) {
if (!isExpression(expression)) {
WorkflowProcess process = ((NodeImpl) getNode()).getProcess();
Expression exprObject = ExpressionHandlerFactory.get(process.getExpressionLanguage(), expression);
if (exprObject.isValid()) {
if (context == null) {
context = ContextFactory.fromNode(this);
}
String varName = (String) process.getMetaData().get(Metadata.VARIABLE);
Object target = varName == null ? this.getProcessInstance().getVariables() : context.getVariable(varName);
return exprObject.eval(target, String.class, context);
}
}
return resolveExpression(expression);
}

protected void handleSLAViolation() {
if (slaCompliance == KogitoProcessInstance.SLA_PENDING) {
InternalProcessRuntime processRuntime = ((InternalProcessRuntime) getProcessInstance().getKnowledgeRuntime().getProcessRuntime());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ private GeneratedInfo<KogitoWorkflowProcess> parseProcess() {
DEFAULT_PACKAGE) : DEFAULT_PACKAGE)
.visibility("Public")
.expressionLanguage(workflow.getExpressionLang())
.metaData(Metadata.VARIABLE, DEFAULT_WORKFLOW_VAR)
.variable(DEFAULT_WORKFLOW_VAR, new ObjectDataType(JsonNode.class), ObjectMapperFactory.listenerAware().createObjectNode())
.type(KogitoWorkflowProcess.SW_TYPE);
ParserContext parserContext =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.time.Duration;
import java.time.format.DateTimeParseException;

import org.kie.kogito.process.expr.ExpressionHandlerFactory;

import io.serverlessworkflow.api.Workflow;
import io.serverlessworkflow.api.interfaces.State;
import io.serverlessworkflow.api.timeouts.TimeoutsDefinition;
Expand All @@ -45,26 +47,30 @@ public static String resolveEventTimeout(State state, Workflow workflow) {
String.format(INVALID_EVENT_TIMEOUT_FOR_STATE_ERROR,
timeouts.getEventTimeout(),
state.getName(),
workflow.getName()));
workflow.getName()),
workflow.getExpressionLang());
return timeouts.getEventTimeout();
} else {
timeouts = workflow.getTimeouts();
if (timeouts != null && timeouts.getEventTimeout() != null) {
validateDuration(timeouts.getEventTimeout(),
String.format(INVALID_EVENT_TIMEOUT_FOR_WORKFLOW_ERROR,
timeouts.getEventTimeout(),
workflow.getName()));
workflow.getName()),
workflow.getExpressionLang());
return timeouts.getEventTimeout();
}
}
return null;
}

private static void validateDuration(String value, String message) {
try {
Duration.parse(value);
} catch (DateTimeParseException e) {
throw new IllegalArgumentException(message, e);
private static void validateDuration(String value, String message, String exprLanguage) {
if (!ExpressionHandlerFactory.get(exprLanguage, value).isValid()) {
try {
Duration.parse(value);
} catch (DateTimeParseException e) {
throw new IllegalArgumentException(message, e);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ private static State mockState(String name, String eventTimeout) {

private static Workflow mockWorkflow(String name) {
Workflow workflow = mock(Workflow.class);
doReturn("jq").when(workflow).getExpressionLang();
doReturn(name).when(workflow).getName();
return workflow;
}
Expand Down

0 comments on commit b73b03c

Please sign in to comment.