Skip to content

Commit

Permalink
[Fix #3694] Avoid generation of fake ProcessInstanceVariableDataEvent
Browse files Browse the repository at this point in the history
  • Loading branch information
fjtirado committed Oct 4, 2024
1 parent 070876f commit e39a7c9
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import org.kie.kogito.jackson.utils.PrefixJsonNode;
import org.kie.kogito.process.expr.Expression;
import org.kie.kogito.serverless.workflow.utils.ExpressionHandlerUtils;
import org.kie.kogito.serverless.workflow.utils.JsonNodeContext;
import org.kie.kogito.serverless.workflow.utils.VariablesHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -207,6 +207,7 @@ private Scope getScope(KogitoProcessContext processInfo) {
childScope.setValue(ExpressionHandlerUtils.SECRET_MAGIC, new PrefixJsonNode<>(ExpressionHandlerUtils::getOptionalSecret));
childScope.setValue(ExpressionHandlerUtils.CONTEXT_MAGIC, new FunctionJsonNode(ExpressionHandlerUtils.getContextFunction(processInfo)));
childScope.setValue(ExpressionHandlerUtils.CONST_MAGIC, ExpressionHandlerUtils.getConstants(processInfo));
VariablesHelper.getAdditionalVariables(processInfo).forEach(childScope::setValue);
return childScope;
}

Expand All @@ -215,8 +216,8 @@ private <T> T eval(JsonNode context, Class<T> returnClass, KogitoProcessContext
throw new IllegalArgumentException("Unable to evaluate content " + context + " using expr " + expr, validationError);
}
TypedOutput output = output(returnClass);
try (JsonNodeContext jsonNode = JsonNodeContext.from(context, processInfo)) {
internalExpr.apply(getScope(processInfo), jsonNode.getNode(), output);
try {
internalExpr.apply(getScope(processInfo), context, output);
return JsonObjectUtils.convertValue(output.getResult(), returnClass);
} catch (JsonQueryException e) {
throw new IllegalArgumentException("Unable to evaluate content " + context + " using expr " + expr, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@
*/
package org.kie.kogito.expr.jsonpath;

import java.util.Map;

import org.kie.kogito.internal.process.runtime.KogitoProcessContext;
import org.kie.kogito.jackson.utils.JsonObjectUtils;
import org.kie.kogito.process.expr.Expression;
import org.kie.kogito.serverless.workflow.utils.ExpressionHandlerUtils;
import org.kie.kogito.serverless.workflow.utils.JsonNodeContext;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
Expand Down Expand Up @@ -61,24 +63,28 @@ private Configuration getConfiguration(KogitoProcessContext context) {
.build();
}

private static boolean isContextAware(JsonNode context, Map<String, JsonNode> additionalVars) {
return !additionalVars.isEmpty() && context instanceof ObjectNode;
}

private <T> T eval(JsonNode context, Class<T> returnClass, KogitoProcessContext processInfo) {
try (JsonNodeContext jsonNode = JsonNodeContext.from(context, processInfo)) {
Configuration jsonPathConfig = getConfiguration(processInfo);
DocumentContext parsedContext = JsonPath.using(jsonPathConfig).parse(jsonNode.getNode());
if (String.class.isAssignableFrom(returnClass)) {
StringBuilder sb = new StringBuilder();
// valid json path is $. or $[
for (String part : expr.split("((?=\\$\\.|\\$\\[))")) {
JsonNode partResult = parsedContext.read(part, JsonNode.class);
sb.append(partResult.isTextual() ? partResult.asText() : partResult.toPrettyString());
}
return (T) sb.toString();
} else {
Object result = parsedContext.read(expr);
return Boolean.class.isAssignableFrom(returnClass) && result instanceof ArrayNode ? (T) Boolean.valueOf(!((ArrayNode) result).isEmpty())
: JsonObjectUtils.convertValue(jsonPathConfig.mappingProvider().map(result, returnClass, jsonPathConfig), returnClass);

Configuration jsonPathConfig = getConfiguration(processInfo);
DocumentContext parsedContext = JsonPath.using(jsonPathConfig).parse(context);
if (String.class.isAssignableFrom(returnClass)) {
StringBuilder sb = new StringBuilder();
// valid json path is $. or $[
for (String part : expr.split("((?=\\$\\.|\\$\\[))")) {
JsonNode partResult = parsedContext.read(part, JsonNode.class);
sb.append(partResult.isTextual() ? partResult.asText() : partResult.toPrettyString());
}
return (T) sb.toString();
} else {
Object result = parsedContext.read(expr);
return Boolean.class.isAssignableFrom(returnClass) && result instanceof ArrayNode ? (T) Boolean.valueOf(!((ArrayNode) result).isEmpty())
: JsonObjectUtils.convertValue(jsonPathConfig.mappingProvider().map(result, returnClass, jsonPathConfig), returnClass);
}

}

private void assign(JsonNode context, Object value, KogitoProcessContext processInfo) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,26 @@
*/
package org.kie.kogito.expr.jsonpath;

import java.util.Map;
import java.util.function.Function;

import org.kie.kogito.internal.process.runtime.KogitoProcessContext;
import org.kie.kogito.jackson.utils.FunctionBaseJsonNode;
import org.kie.kogito.jackson.utils.PrefixJsonNode;
import org.kie.kogito.serverless.workflow.utils.ExpressionHandlerUtils;
import org.kie.kogito.serverless.workflow.utils.VariablesHelper;

import com.fasterxml.jackson.databind.JsonNode;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;

public class WorkflowJacksonJsonNodeJsonProvider extends JacksonJsonNodeJsonProvider {

private KogitoProcessContext context;
private Map<String, JsonNode> variables;

public WorkflowJacksonJsonNodeJsonProvider(KogitoProcessContext context) {
this.context = context;
this.variables = VariablesHelper.getAdditionalVariables(context);
}

@Override
Expand All @@ -50,7 +55,7 @@ public Object getMapValue(Object obj, String key) {
case "$" + ExpressionHandlerUtils.CONST_MAGIC:
return ExpressionHandlerUtils.getConstants(context);
default:
return super.getMapValue(obj, key);
return variables.containsKey(key) ? variables.get(key) : super.getMapValue(obj, key);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import org.kie.kogito.serverless.workflow.parser.FunctionTypeHandlerFactory;
import org.kie.kogito.serverless.workflow.parser.ParserContext;
import org.kie.kogito.serverless.workflow.parser.VariableInfo;
import org.kie.kogito.serverless.workflow.utils.JsonNodeContext;
import org.kie.kogito.serverless.workflow.utils.VariablesHelper;

import io.serverlessworkflow.api.Workflow;
import io.serverlessworkflow.api.actions.Action;
Expand Down Expand Up @@ -181,7 +181,7 @@ private TimerNodeFactory<?> createTimerNode(RuleFlowNodeContainerFactory<?, ?> f
factory.subProcessNode(parserContext.newId()).name(subFlowRef.getWorkflowId()).processId(subFlowRef.getWorkflowId()).waitForCompletion(true),
inputVar,
outputVar);
JsonNodeContext.getEvalVariables(factory.getNode()).forEach(v -> subProcessNode.inMapping(v.getName(), v.getName()));
VariablesHelper.getEvalVariables(factory.getNode()).forEach(v -> subProcessNode.inMapping(v.getName(), v.getName()));
return subProcessNode;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -41,14 +40,33 @@
import org.kie.kogito.internal.process.runtime.KogitoNodeInstance;
import org.kie.kogito.internal.process.runtime.KogitoProcessContext;
import org.kie.kogito.jackson.utils.JsonObjectUtils;
import org.kie.kogito.serverless.workflow.SWFConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class JsonNodeContext implements AutoCloseable {
public class VariablesHelper {

private final JsonNode jsonNode;
private final Set<String> keys;
private static final Set<String> PREDEFINED_KEYS = Set.of(SWFConstants.DEFAULT_WORKFLOW_VAR, SWFConstants.INPUT_WORKFLOW_VAR);
private static final Logger logger = LoggerFactory.getLogger(VariablesHelper.class);

private VariablesHelper() {
}

public static Map<String, JsonNode> getAdditionalVariables(KogitoProcessContext context) {
Map<String, JsonNode> variables = new HashMap<>();
KogitoNodeInstance nodeInstance = context.getNodeInstance();
if (nodeInstance != null) {
NodeInstanceContainer container = nodeInstance instanceof NodeInstanceContainer ? (NodeInstanceContainer) nodeInstance : nodeInstance.getNodeInstanceContainer();
while (container instanceof ContextableInstance) {
addVariablesFromContext((ContextableInstance) container, variables);
container = container instanceof KogitoNodeInstance ? ((KogitoNodeInstance) container).getNodeInstanceContainer() : null;
}
}
logger.debug("Additional variables for expression evaluation are {}", variables);
return variables;
}

public static Stream<Variable> getEvalVariables(Node node) {
if (node instanceof ForEachNode) {
Expand All @@ -66,55 +84,23 @@ private static Stream<Variable> getEvalVariables(ContextableInstance containerIn

private static Stream<Variable> getEvalVariables(ContextContainer container) {
VariableScope variableScope = (VariableScope) container.getDefaultContext(VariableScope.VARIABLE_SCOPE);
return variableScope.getVariables().stream().filter(v -> v.getMetaData(Metadata.EVAL_VARIABLE) != null);
}

public static JsonNodeContext from(JsonNode jsonNode, KogitoProcessContext context) {
Map<String, JsonNode> map = new HashMap<>();
if (jsonNode.isObject()) {
ObjectNode objectNode = (ObjectNode) jsonNode;
addVariablesFromContext(objectNode, context, map);
}
return new JsonNodeContext(jsonNode, map.keySet());
return variableScope.getVariables().stream().filter(VariablesHelper::isEvalVariable);
}

public JsonNode getNode() {
return jsonNode;
private static boolean isEvalVariable(Variable v) {
Object isEval = v.getMetaData(Metadata.EVAL_VARIABLE);
return isEval instanceof Boolean ? ((Boolean) isEval).booleanValue() : false;
}

private JsonNodeContext(JsonNode jsonNode, Set<String> keys) {
this.jsonNode = jsonNode;
this.keys = keys;
}

private static void addVariablesFromContext(ObjectNode jsonNode, KogitoProcessContext processInfo, Map<String, JsonNode> variables) {
KogitoNodeInstance nodeInstance = processInfo.getNodeInstance();
if (nodeInstance != null) {
NodeInstanceContainer container = nodeInstance instanceof NodeInstanceContainer ? (NodeInstanceContainer) nodeInstance : nodeInstance.getNodeInstanceContainer();
while (container instanceof ContextableInstance) {
getVariablesFromContext(jsonNode, (ContextableInstance) container, variables);
container = container instanceof KogitoNodeInstance ? ((KogitoNodeInstance) container).getNodeInstanceContainer() : null;
}
}
variables.forEach(jsonNode::set);
}

private static void getVariablesFromContext(ObjectNode jsonNode, ContextableInstance node, Map<String, JsonNode> variables) {
private static void addVariablesFromContext(ContextableInstance node, Map<String, JsonNode> variables) {
VariableScopeInstance variableScope = (VariableScopeInstance) node.getContextInstance(VariableScope.VARIABLE_SCOPE);
if (variableScope != null) {
Collection<String> evalVariables = getEvalVariables(node).map(Variable::getName).collect(Collectors.toList());
for (Entry<String, Object> e : variableScope.getVariables().entrySet()) {
if (evalVariables.contains(e.getKey()) || node instanceof WorkflowProcessInstance && !Objects.equals(jsonNode, e.getValue())) {
if (evalVariables.contains(e.getKey()) || node instanceof WorkflowProcessInstance && !PREDEFINED_KEYS.contains(e.getKey())) {
variables.putIfAbsent(e.getKey(), JsonObjectUtils.fromValue(e.getValue()));
}
}
}
}

@Override
public void close() {
if (!keys.isEmpty()) {
keys.forEach(((ObjectNode) jsonNode)::remove);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"functionRef": {
"refName": "division",
"arguments": {
"dividend": ".item",
"dividend": "$item",
"divisor" : ".divisor"
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"functionRef": {
"refName": "division",
"arguments": {
"QUERY_dividend": ".item",
"QUERY_dividend": "$item",
"QUERY_divisor" : ".divisor"
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{
"name": "multiply",
"type": "expression",
"operation": ".number*.constant"
"operation": "$number*.constant"
}
],
"states": [
Expand Down

0 comments on commit e39a7c9

Please sign in to comment.