Skip to content

Commit

Permalink
Merge pull request #2281 from GDLMadushanka/fixExpression
Browse files Browse the repository at this point in the history
Add grammer changes and fix tests
  • Loading branch information
GDLMadushanka authored Jan 10, 2025
2 parents fa80d9f + 0e5ef90 commit 9bfd69c
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ JSONPATH_PARAMS: 'in' | 'nin' | 'subsetof' | 'anyof' | 'noneof' | 'size' | 'emp
JSONPATH_FUNCTIONS: 'length()' | 'size()' | 'min()' | 'max()' | 'avg()' | 'sum()' | 'stddev()' | 'keys()' | 'first()' | 'last()';

// Tokens for identifiers, operators, and keywords
VAR: 'var';
VAR: 'vars';
PAYLOAD: 'payload' | '$';
HEADERS: 'headers';
CONFIG: 'config';
CONFIG: 'configs';
PARAMS: 'params';
PROPERTY: 'props' | 'properties';
AND: 'and' | '&&';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ factor
| LPAREN expression RPAREN
;

keywords
: DOT VAR
| DOT PAYLOAD
| DOT HEADERS
| DOT CONFIG
| DOT PARAMS
| DOT PROPERTY
;

configAccess
: CONFIG propertyName
;
Expand All @@ -61,6 +70,7 @@ propertyAccess

propertyName
: DOT ID
| keywords
| (DOT)? LBRACKET STRING_LITERAL RBRACKET
;

Expand All @@ -74,9 +84,10 @@ literal

jsonPathExpression
:( DOT JSONPATH_FUNCTIONS
|DOUBLE_DOT ASTERISK
| DOUBLE_DOT ASTERISK
| DOUBLE_DOT ID
| DOT ID
| keywords
| (DOT)? LBRACKET arrayIndex RBRACKET
| DOT ASTERISK
| DOUBLE_DOT ID (LBRACKET arrayIndex RBRACKET)?)+
Expand All @@ -86,6 +97,7 @@ jsonPathExpression
variableAccess
: VAR ( DOT ID
| DOT STRING_LITERAL
| keywords
| (DOT)? LBRACKET STRING_LITERAL RBRACKET // Bracket notation: var["variableName"]
)
( jsonPathExpression )?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValu
result = variable;
} else if (variable instanceof Map) {
if (StringUtils.isNotEmpty(expressionToEvaluate)) {
expressionToEvaluate = expressionToEvaluate.startsWith(".") ? "var" + expressionToEvaluate
: "var." + expressionToEvaluate;
expressionToEvaluate = expressionToEvaluate.startsWith(".") ? "vars" + expressionToEvaluate
: "vars." + expressionToEvaluate;
}
String[] keyAndExpression = ExpressionUtils.extractVariableAndJsonPath(expressionToEvaluate);
String key = keyAndExpression[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import org.apache.synapse.util.synapse.expression.context.EvaluationContext;

/**
* Represents a node in the AST that holds a signed expression. ex: ( -var.num1 )
* Represents a node in the AST that holds a signed expression. ex: ( -vars.num1 )
*/
public class SignedExpressionNode implements ExpressionNode {
private final ExpressionNode expression;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,27 @@ public static String getCharset(String charsetName) {
/**
* Extracts the variable name and JSONPath from the input expression.
*
* @param input The input string (e.g., var.abc.students[1].name or var["abc"]["students"][1].name).
* @param input The input string (e.g., vars.abc.students[1].name or vars["abc"]["students"][1].name).
* @return A string array where index 0 is the variable name and index 1 is the JSONPath.
*/
public static String[] extractVariableAndJsonPath(String input) {
if (input.startsWith("var.[\"")) {
String remaining = input.substring(6);
String VAR_DOT_ARR = "vars.[\"";
String VAR_ARR = "vars[\"";
String VAR_DOT = "vars.";
if (input.startsWith(VAR_DOT_ARR)) {
String remaining = input.substring(VAR_DOT_ARR.length());
int endBracketIndex = remaining.indexOf("\"]");
String variableName = remaining.substring(0, endBracketIndex);
String expression = remaining.substring(endBracketIndex + 2);
return new String[]{variableName, expression};
} else if (input.startsWith("var[\"")) {
String remaining = input.substring(5);
} else if (input.startsWith(VAR_ARR)) {
String remaining = input.substring(VAR_ARR.length());
int endBracketIndex = remaining.indexOf("\"]");
String variableName = remaining.substring(0, endBracketIndex);
String expression = remaining.substring(endBracketIndex + 2);
return new String[]{variableName, expression};
} else if (input.startsWith("var.")) {
String remaining = input.substring(4);
} else if (input.startsWith(VAR_DOT)) {
String remaining = input.substring(VAR_DOT.length());
int endDotIndex = remaining.indexOf(".");
int beginArrIndex = remaining.indexOf("[");
String variableName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public static Collection provideConfigsForPrepareReplacementValueWithEscapeXmlCh
{
"{\n" +
" \"description\": \"${payload.test1}\",\n" +
" \"path\": ${var.path}\n" +
" \"path\": ${vars.path}\n" +
"}",
"json",
"application/json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public void testsInLineSynapseExpressionTemplate4() throws Exception {
jsonObject.addProperty("street", "Palm Grove");
jsonObject.addProperty("city", "Colombo");
mc.setVariable("address", jsonObject);
String inlineExpression = "Processing user with age : ${var.age} lives at ${var.address}";
String inlineExpression = "Processing user with age : ${vars.age} lives at ${vars.address}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
Assert.assertFalse("Inline expression content aware should be false", isContentAware);
Expand All @@ -160,8 +160,8 @@ public void testsInLineSynapseExpressionTemplate5() throws Exception {
jsonObject.addProperty("level", "3");
mc.setVariable("experience", jsonObject);
mc.setProperty("duration", "years");
String inlineExpression = "Processing user : ${payload.team[0].name}, role : ${var.role}, " +
"experience : ${var.experience.level} ${properties.synapse.duration}";
String inlineExpression = "Processing user : ${payload.team[0].name}, role : ${vars.role}, " +
"experience : ${vars.experience.level} ${properties.synapse.duration}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
Assert.assertTrue("Inline expression content aware should be true", isContentAware);
Expand All @@ -180,7 +180,7 @@ public void testsInLineSynapseExpressionTemplate6() throws Exception {
MessageContext mc = TestUtils.getTestContextJson(payload, null);
mc.setVariable("endpoint", "https://test.wso2.com/");
mc.setProperty("method", "get");
String inlineExpression = "Processing using endpoint : ${var.endpoint}, method : ${properties.synapse.method}, role : ${payload.team[2].role}";
String inlineExpression = "Processing using endpoint : ${vars.endpoint}, method : ${properties.synapse.method}, role : ${payload.team[2].role}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
Assert.assertTrue("Inline expression content aware should be true", isContentAware);
Expand All @@ -205,7 +205,7 @@ public void testsInLineSynapseExpressionTemplate7() throws Exception {

MessageContext mc = TestUtils.getTestContext(xmlPayload);
mc.setVariable("endpoint", "https://test.wso2.com/");
String inlineExpression = "Using endpoint : ${var.endpoint} to process book : ${xpath('//catalog/book[1]')}";
String inlineExpression = "Using endpoint : ${vars.endpoint} to process book : ${xpath('//catalog/book[1]')}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
Assert.assertTrue("Inline expression content aware should be true", isContentAware);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void testIfElse() {
Assert.assertEquals("", TestUtils.evaluateExpression("45 == ( 5 + 34 ? true : 456)"));
Assert.assertEquals("", TestUtils.evaluateExpressionWithPayload("45 == ( $[\"null\"] ? true : 456)", 1));
Assert.assertEquals("[22.99]", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.num1 > var.num2 ? $..book[?(@.author =~ /.*Tolkien/i)].price " +
"vars.num1 > vars.num2 ? $..book[?(@.author =~ /.*Tolkien/i)].price " +
": $..book[(@.\"length\"-1)].title", 2,1));
Assert.assertEquals("", TestUtils.evaluateExpression("null == $[\"null\"] ? 123 : 456"));
Assert.assertEquals("", TestUtils.evaluateExpressionWithPayload(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ public void testComplexUsages() throws JaxenException {
Assert.assertTrue(synapsePath.isContentAware());
synapsePath = new SynapseExpression("$..book[?(@.category==\"payload.category\")]");
Assert.assertTrue(synapsePath.isContentAware());
synapsePath = new SynapseExpression("var.books[?(@.category==payload.category)]");
synapsePath = new SynapseExpression("vars.books[?(@.category==payload.category)]");
Assert.assertTrue(synapsePath.isContentAware());
synapsePath = new SynapseExpression("var.books[?(@.category==$.category)]");
synapsePath = new SynapseExpression("vars.books[?(@.category==$.category)]");
Assert.assertTrue(synapsePath.isContentAware());
}

Expand All @@ -65,27 +65,27 @@ public void testWithXpath() throws JaxenException {
Assert.assertTrue(synapsePath.isContentAware());
synapsePath = new SynapseExpression("xpath(\"/student\")");
Assert.assertTrue(synapsePath.isContentAware());
synapsePath = new SynapseExpression("xpath(\"//*\") + var.a$bc");
synapsePath = new SynapseExpression("xpath(\"//*\") + vars.a$bc");
Assert.assertTrue(synapsePath.isContentAware());
synapsePath = new SynapseExpression("xpath(\"$ctx:bla\") + $.age");
Assert.assertTrue(synapsePath.isContentAware());
synapsePath = new SynapseExpression("var.num1 + var.[\"payload\"] + xpath(\"//num3\")");
synapsePath = new SynapseExpression("vars.num1 + vars.[\"payload\"] + xpath(\"//num3\")");
Assert.assertTrue(synapsePath.isContentAware());
synapsePath = new SynapseExpression("var.num1 + var.[\"payload\"] + xpath(\"$ctx:num3\")");
synapsePath = new SynapseExpression("vars.num1 + vars.[\"payload\"] + xpath(\"$ctx:num3\")");
Assert.assertFalse(synapsePath.isContentAware());
}

@Test
public void testNegativeCases() throws JaxenException {
SynapseExpression synapsePath = new SynapseExpression("length(var.abc)");
SynapseExpression synapsePath = new SynapseExpression("length(vars.abc)");
Assert.assertFalse(synapsePath.isContentAware());
synapsePath = new SynapseExpression("var[\"payload\"]");
synapsePath = new SynapseExpression("vars[\"payload\"]");
Assert.assertFalse(synapsePath.isContentAware());
synapsePath = new SynapseExpression("5 + var[\"payload\"].age");
Assert.assertFalse(synapsePath.isContentAware());
synapsePath = new SynapseExpression("var.a$.bc");
synapsePath = new SynapseExpression("vars.a$.bc");
Assert.assertFalse(synapsePath.isContentAware());
synapsePath = new SynapseExpression("var.books[?(@.category==\"payload.category\")]");
synapsePath = new SynapseExpression("vars.books[?(@.category==\"payload.category\")]");
Assert.assertFalse(synapsePath.isContentAware());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,45 +113,60 @@ public void testJSONPath() {

@Test
public void testVariableAccess() {
Assert.assertEquals("John", TestUtils.evaluateExpressionWithPayloadAndVariables("var.name", 1, 1));
Assert.assertEquals("10", TestUtils.evaluateExpressionWithPayloadAndVariables("var.num1", 1, 1));
Assert.assertEquals("John", TestUtils.evaluateExpressionWithPayloadAndVariables("vars.name", 1, 1));
Assert.assertEquals("10", TestUtils.evaluateExpressionWithPayloadAndVariables("vars.num1", 1, 1));
Assert.assertEquals("-29.0", TestUtils.evaluateExpressionWithPayloadAndVariables(
"(var.num1 * var.num3) - var.num2 + payload.index", 1, 1));
"(vars.num1 * vars.num3) - vars.num2 + payload.index", 1, 1));
Assert.assertEquals("true", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.num1 >= var.num2", 1, 1));
"vars.num1 >= vars.num2", 1, 1));
Assert.assertEquals("2", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.json3[1]", 0, 2));
"vars.json3[1]", 0, 2));
Assert.assertEquals("2", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var[\"json3\"][1]", 0, 2));
"vars[\"json3\"][1]", 0, 2));
Assert.assertEquals("[\"The Lord of the Rings\"]", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var[\"json2\"][\"store\"][\"book\"][?(@.author=='J.R.R. Tolkien')].title", 0, 2));
"vars[\"json2\"][\"store\"][\"book\"][?(@.author=='J.R.R. Tolkien')].title", 0, 2));
Assert.assertEquals("[\"Moby Dick\",\"To Kill a Mockingbird\"]",
TestUtils.evaluateExpressionWithPayloadAndVariables(
"var[\"json2\"][\"store\"][\"book\"][1,3].title", 0, 2));
"vars[\"json2\"][\"store\"][\"book\"][1,3].title", 0, 2));
Assert.assertEquals("[\"Animal Farm\",\"The Diary of a Young Girl\"]",
TestUtils.evaluateExpressionWithPayloadAndVariables(
"var[\"json2\"][\"store\"][\"book\"][-2:].title", 0, 2));
"vars[\"json2\"][\"store\"][\"book\"][-2:].title", 0, 2));
Assert.assertEquals("[\"Moby Dick\",\"The Lord of the Rings\",\"To Kill a Mockingbird\",\"Animal Farm\"]",
TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.json2.store.book[?(@.category=='fiction')].title", 0, 2));
"vars.json2.store.book[?(@.category=='fiction')].title", 0, 2));
Assert.assertEquals("[\"The Lord of the Rings\",\"To Kill a Mockingbird\"]",
TestUtils.evaluateExpressionWithPayloadAndVariables(
"var[\"json2\"][\"store\"][\"book\"][?(@.price > payload.expensive)].title", 2, 2));
"vars[\"json2\"][\"store\"][\"book\"][?(@.price > payload.expensive)].title", 2, 2));
Assert.assertEquals("[\"The Lord of the Rings\",\"To Kill a Mockingbird\"]",
TestUtils.evaluateExpressionWithPayloadAndVariables(
"var[\"json2\"].store.[\"book\"][?(@.price > payload.expensive)].title", 2, 2));
"vars[\"json2\"].store.[\"book\"][?(@.price > payload.expensive)].title", 2, 2));
Assert.assertEquals("[\"The Lord of the Rings\",\"To Kill a Mockingbird\"]",
TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.[\"json2\"].store.[\"book\"][?(@.price > payload.expensive)].title", 2, 2));
"vars.[\"json2\"].store.[\"book\"][?(@.price > payload.expensive)].title", 2, 2));
Assert.assertEquals("", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.random", 0, 1));
"vars.random", 0, 1));
Assert.assertEquals("", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.num1[0]", 0, 1));
"vars.num1[0]", 0, 1));
Assert.assertEquals("201", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.fileRead_1.['attributes'].statusCode", 0, 3));
"vars.fileRead_1.['attributes'].statusCode", 0, 3));
Assert.assertEquals("101", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var[\"fileRead_1\"][\"headers\"]['Content-Length']", 0, 3));
Assert.assertEquals("[\"Moby Dick\",\"To Kill a Mockingbird\"]", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.fileRead_1['payload'][\"store\"][\"book\"][1,3].title", 2, 3));
"vars[\"fileRead_1\"][\"headers\"]['Content-Length']", 0, 3));
Assert.assertEquals("[\"Moby Dick\",\"To Kill a Mockingbird\"]",
TestUtils.evaluateExpressionWithPayloadAndVariables(
"vars.fileRead_1['payload'][\"store\"][\"book\"][1,3].title", 2, 3));
}

@Test
public void testPayloadAccessWithKeywords() {
Assert.assertEquals("2", TestUtils.evaluateExpressionWithPayloadAndVariables(
"payload.payload.vars.pqr", 4, 0));
Assert.assertEquals("8", TestUtils.evaluateExpressionWithPayloadAndVariables(
"payload.payload.vars.pqr * payload.payload.vars.configs.payload.iop", 4, 0));
Assert.assertEquals("2", TestUtils.evaluateExpressionWithPayloadAndVariables(
"vars.payload.payload.vars.pqr", 0, 2));
Assert.assertEquals("2", TestUtils.evaluateExpressionWithPayloadAndVariables(
"vars.vars.payload.vars.pqr", 0, 2));
Assert.assertEquals("6", TestUtils.evaluateExpressionWithPayloadAndVariables(
"vars.vars.payload.vars.pqr + vars.payload.payload.vars.configs.payload.iop ", 0, 2));
}
}
Loading

0 comments on commit 9bfd69c

Please sign in to comment.