From c504854f3c667907ee9e3b72fa547c7506d9b118 Mon Sep 17 00:00:00 2001 From: Ingo Richtsmeier Date: Fri, 10 Jan 2025 11:39:41 +0100 Subject: [PATCH] Convert execution.getVariable("a") to a valid FEEL expression (#1092) --- .../ExpressionTransformationResult.java | 30 +++++++- .../expression/ExpressionTransformer.java | 3 +- .../impl/CompletionConditionVisitor.java | 2 +- .../impl/ConditionExpressionVisitor.java | 2 +- .../impl/attribute/CollectionVisitor.java | 2 +- .../element/InputOutputParameterVisitor.java | 2 +- .../converter/BpmnConverterTest.java | 28 +++++-- .../converter/ExpressionTransformerTest.java | 17 ++++- .../resources/expression-get-variable.bpmn | 73 +++++++++++++++++++ 9 files changed, 142 insertions(+), 17 deletions(-) create mode 100644 backend-diagram-converter/core/src/test/resources/expression-get-variable.bpmn diff --git a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/expression/ExpressionTransformationResult.java b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/expression/ExpressionTransformationResult.java index a23251848..b4ee05b49 100644 --- a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/expression/ExpressionTransformationResult.java +++ b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/expression/ExpressionTransformationResult.java @@ -2,10 +2,17 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ExpressionTransformationResult { + + private static final Logger LOG = LoggerFactory.getLogger(ExpressionTransformationResult.class); + private static final Pattern methodInvocationPattern = Pattern.compile("\\.[\\w]*\\(.*\\)"); private static final Pattern executionPattern = Pattern.compile("execution\\."); + private static final Pattern executionGetVariablePattern = + Pattern.compile("execution.getVariable"); private final String juelExpression; private final String feelExpression; @@ -23,12 +30,29 @@ public String getFeelExpression() { } public Boolean hasMethodInvocation() { + if (hasExecutionGetVariable()) { + return false; + } Matcher m = methodInvocationPattern.matcher(juelExpression); - return m.find(); + boolean methodMatch = m.find(); + LOG.debug("{} contains method invocation: {}", juelExpression, methodMatch); + return methodMatch; } - public Boolean hasExecution() { + public Boolean hasExecutionOnly() { + if (hasExecutionGetVariable()) { + return false; + } Matcher m = executionPattern.matcher(juelExpression); - return m.find(); + boolean executionOnlyMatch = m.find(); + LOG.debug("{} contains execution only: {}", juelExpression, executionOnlyMatch); + return executionOnlyMatch; + } + + public Boolean hasExecutionGetVariable() { + Matcher m = executionGetVariablePattern.matcher(juelExpression); + boolean executionGetVariableMatch = m.find(); + LOG.debug("{} contains execution.getVariable: {}", juelExpression, executionGetVariableMatch); + return executionGetVariableMatch; } } diff --git a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/expression/ExpressionTransformer.java b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/expression/ExpressionTransformer.java index 8cc73d83e..ac9b0d92b 100644 --- a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/expression/ExpressionTransformer.java +++ b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/expression/ExpressionTransformer.java @@ -65,7 +65,8 @@ private String handleExpression(String expression) { .replaceAll("!\\(([^\\(\\)]*)\\)", "not($1)") .replaceAll(" && ", " and ") .replaceAll(" \\|\\| ", " or ") - .replaceAll("'", "\""); + .replaceAll("'", "\"") + .replaceAll("execution\\.getVariable\\(\"(.*)\"\\)", "$1"); // increment all indexes Pattern pattern = Pattern.compile("\\[(\\d*)\\]"); Matcher m = pattern.matcher(replaced); diff --git a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/CompletionConditionVisitor.java b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/CompletionConditionVisitor.java index 44027c32e..ebe784021 100644 --- a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/CompletionConditionVisitor.java +++ b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/CompletionConditionVisitor.java @@ -28,7 +28,7 @@ protected void visitBpmnElement(DomElementVisitorContext context) { .getBpmnMultiInstanceLoopCharacteristics() .setCompletionCondition(transformationResult.getFeelExpression())); Message message; - if (transformationResult.hasExecution()) { + if (transformationResult.hasExecutionOnly()) { message = MessageFactory.completionConditionExecution( transformationResult.getJuelExpression(), transformationResult.getFeelExpression()); diff --git a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/ConditionExpressionVisitor.java b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/ConditionExpressionVisitor.java index db535d38b..ffbeedf42 100644 --- a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/ConditionExpressionVisitor.java +++ b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/ConditionExpressionVisitor.java @@ -94,7 +94,7 @@ private void handleJuelExpression(DomElementVisitorContext context) { context.addConversion( SequenceFlowConvertible.class, conversion -> conversion.setConditionExpression(transformationResult.getFeelExpression())); - if (transformationResult.hasExecution()) { + if (transformationResult.hasExecutionOnly()) { context.addMessage( MessageFactory.conditionExpressionExecution( transformationResult.getJuelExpression(), transformationResult.getFeelExpression())); diff --git a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/attribute/CollectionVisitor.java b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/attribute/CollectionVisitor.java index 2d074e5f8..d5bb9a0f4 100644 --- a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/attribute/CollectionVisitor.java +++ b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/attribute/CollectionVisitor.java @@ -30,7 +30,7 @@ protected Message visitSupportedAttribute(DomElementVisitorContext context, Stri .setInputCollection(transformationResult.getFeelExpression())); context.addMessage(MessageFactory.collectionHint()); Message message; - if (transformationResult.hasExecution()) { + if (transformationResult.hasExecutionOnly()) { message = MessageFactory.collectionExecution( attributeLocalName(), diff --git a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/element/InputOutputParameterVisitor.java b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/element/InputOutputParameterVisitor.java index d751e188d..b76a733aa 100644 --- a/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/element/InputOutputParameterVisitor.java +++ b/backend-diagram-converter/core/src/main/java/org/camunda/community/migration/converter/visitor/impl/element/InputOutputParameterVisitor.java @@ -42,7 +42,7 @@ protected Message visitCamundaElement(DomElementVisitorContext context) { abstractTaskConversion.addZeebeIoMapping( direction, transformationResult.getFeelExpression(), name)); Message resultMessage; - if (transformationResult.hasExecution()) { + if (transformationResult.hasExecutionOnly()) { resultMessage = MessageFactory.inputOutputParameterExecution( localName(), diff --git a/backend-diagram-converter/core/src/test/java/org/camunda/community/migration/converter/BpmnConverterTest.java b/backend-diagram-converter/core/src/test/java/org/camunda/community/migration/converter/BpmnConverterTest.java index a08c5ed5e..213b833e9 100644 --- a/backend-diagram-converter/core/src/test/java/org/camunda/community/migration/converter/BpmnConverterTest.java +++ b/backend-diagram-converter/core/src/test/java/org/camunda/community/migration/converter/BpmnConverterTest.java @@ -327,6 +327,21 @@ void testInternalScript_8_1() { .isEqualTo("Script was set to header 'script'. Please review."); } + @Test + void testExcutionGetVariable() { + BpmnDiagramCheckResult result = loadAndCheck("expression-get-variable.bpmn"); + List equalsYesMessage = + result.getResult("GetVariableEqualsYesFlow").getMessages(); + assertThat(equalsYesMessage).hasSize(1); + assertThat(equalsYesMessage.get(0).getSeverity()).isEqualTo(Severity.REVIEW); + assertThat(equalsYesMessage.get(0).getMessage()).contains("-> '=exampleVar = \"yes\""); + List notEqualsYesMessage = + result.getResult("GetVariableNotEqualsYesFlow").getMessages(); + assertThat(notEqualsYesMessage).hasSize(1); + assertThat(notEqualsYesMessage.get(0).getSeverity()).isEqualTo(Severity.REVIEW); + assertThat(notEqualsYesMessage.get(0).getMessage()).contains("-> '=exampleVar != \"yes\""); + } + @Test void testExpressionWithMethodInvocation() { BpmnDiagramCheckResult result = loadAndCheck("expression-method-invocation.bpmn"); @@ -338,9 +353,9 @@ void testExpressionWithMethodInvocation() { List executionIsUsedMessage = result.getResult("ExecutionIsUsedSequenceFlow").getMessages(); assertThat(executionIsUsedMessage).hasSize(1); - assertThat(executionIsUsedMessage.get(0).getSeverity()).isEqualTo(Severity.TASK); + assertThat(executionIsUsedMessage.get(0).getSeverity()).isEqualTo(Severity.REVIEW); assertThat(executionIsUsedMessage.get(0).getMessage()) - .contains("'execution' is not available in FEEL"); + .contains("-> '=input != null and input > 5"); List methodInvocationIsUsedMessage = result.getResult("MethodInvocationIsUsedSequenceFlow").getMessages(); @@ -401,13 +416,12 @@ void testMultiInstanceConfigurationWithExecution() { assertThat(messages.get(0).getSeverity()).isEqualTo(Severity.TASK); assertThat(messages.get(0).getMessage()).contains("Collecting results"); - assertThat(messages.get(1).getSeverity()).isEqualTo(Severity.TASK); - assertThat(messages.get(1).getMessage()) - .contains(Arrays.asList("collection", "'execution' is not available in FEEL")); + assertThat(messages.get(1).getSeverity()).isEqualTo(Severity.REVIEW); + assertThat(messages.get(1).getMessage()).contains(Arrays.asList("collection", "-> '=myList'")); - assertThat(messages.get(2).getSeverity()).isEqualTo(Severity.TASK); + assertThat(messages.get(2).getSeverity()).isEqualTo(Severity.REVIEW); assertThat(messages.get(2).getMessage()) - .contains(Arrays.asList("Completion condition", "'execution' is not available in FEEL")); + .contains(Arrays.asList("Completion condition", "-> '=complete = true'")); assertThat(messages.get(3).getSeverity()).isEqualTo(Severity.INFO); } diff --git a/backend-diagram-converter/core/src/test/java/org/camunda/community/migration/converter/ExpressionTransformerTest.java b/backend-diagram-converter/core/src/test/java/org/camunda/community/migration/converter/ExpressionTransformerTest.java index 94879a931..70fac4427 100644 --- a/backend-diagram-converter/core/src/test/java/org/camunda/community/migration/converter/ExpressionTransformerTest.java +++ b/backend-diagram-converter/core/src/test/java/org/camunda/community/migration/converter/ExpressionTransformerTest.java @@ -9,6 +9,7 @@ import org.camunda.community.migration.converter.expression.ExpressionTransformer; import org.junit.jupiter.api.DynamicContainer; import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; public class ExpressionTransformerTest { @@ -57,7 +58,8 @@ public Stream shouldResolveExpression() { expression("${empty donut || coffee}").isMappedTo("=donut=null or coffee"), expression("${not empty donut || coffee}").isMappedTo("=not(donut=null) or coffee"), expression("${not(empty donut || coffee)}").isMappedTo("=not(donut=null or coffee)"), - expression("${execution.getVariable(\"a\")}").hasUsedExecution(true), + expression("${execution.getVariable(\"a\")}").isMappedTo("=a"), + expression("${execution.getProcessInstanceId()}").hasUsedExecution(true), expression("${myexecutionContext.isSpecial()}").hasUsedExecution(false), expression("${var.getSomething()}").hasMethodInvocation(true), expression("${!dauerbuchungVoat21Ids.isEmpty()}").hasMethodInvocation(true), @@ -108,8 +110,19 @@ public ExpressionTestBuilder hasUsedExecution(boolean expected) { tests.add( DynamicTest.dynamicTest( String.format("Expect %s execution used", expected ? "a" : "no"), - () -> assertThat(result.hasExecution()).isEqualTo(expected))); + () -> assertThat(result.hasExecutionOnly()).isEqualTo(expected))); return this; } } + + @Test + public void testExpressions() { + ExpressionTransformationResult underTest = + new ExpressionTransformationResult("execution.", null); + assertThat(underTest.hasExecutionOnly()).isEqualTo(true); + underTest = new ExpressionTransformationResult("execution.getVariable", null); + assertThat(underTest.hasExecutionOnly()).isEqualTo(false); + underTest = new ExpressionTransformationResult("execution.getProcessInstanceId()", null); + assertThat(underTest.hasExecutionOnly()).isEqualTo(true); + } } diff --git a/backend-diagram-converter/core/src/test/resources/expression-get-variable.bpmn b/backend-diagram-converter/core/src/test/resources/expression-get-variable.bpmn new file mode 100644 index 000000000..0bd0b1519 --- /dev/null +++ b/backend-diagram-converter/core/src/test/resources/expression-get-variable.bpmn @@ -0,0 +1,73 @@ + + + + + Flow_1c8n89f + + + Flow_1c8n89f + GetVariableEqualsYesFlow + GetVariableNotEqualsYesFlow + + + + GetVariableEqualsYesFlow + + + ${execution.getVariable("exampleVar") == "yes"} + + + GetVariableNotEqualsYesFlow + + + ${execution.getVariable("exampleVar") != "yes"} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +