Skip to content

Commit 6467ccd

Browse files
committed
Add function param support
Add function param supprot and other improvements. Related to wso2/product-micro-integrator/issues/3749
1 parent 4ea7214 commit 6467ccd

17 files changed

+176
-82
lines changed

modules/core/src/main/java/org/apache/synapse/SynapseConstants.java

+1
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,7 @@ public enum ENDPOINT_TIMEOUT_TYPE { ENDPOINT_TIMEOUT, GLOBAL_TIMEOUT, HTTP_CONNE
678678
public static final String AXIS2 = "axis2";
679679
public static final String QUERY_PARAM = "queryParams";
680680
public static final String URI_PARAM = "uriParams";
681+
public static final String FUNC_PARAM = "functionParams";
681682

682683
public static final String UNKNOWN = "unknown";
683684
public static final String VAULT_LOOKUP = "wso2:vault-lookup('";

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/ArgumentListNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public List<ExpressionNode> getArguments() {
4040
}
4141

4242
@Override
43-
public ExpressionResult evaluate(EvaluationContext context) {
43+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) {
4444
return null;
4545
}
4646

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/ArrayIndexNode.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ public ArrayIndexNode(ArgumentListNode arguments, char separator) {
3535
}
3636

3737
@Override
38-
public ExpressionResult evaluate(EvaluationContext context) {
38+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) {
3939
List<String> indexList = new ArrayList<>();
4040
for (ExpressionNode index : indexArray) {
4141
if (index == null) {
4242
indexList.add("");
4343
continue;
4444
}
45-
ExpressionResult result = index.evaluate(context);
45+
ExpressionResult result = index.evaluate(context, isObjectValue);
4646
if (result != null) {
4747
indexList.add(result.asString());
4848
}

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/BinaryOperationNode.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ public BinaryOperationNode(ExpressionNode left, String operator, ExpressionNode
7171
}
7272

7373
@Override
74-
public ExpressionResult evaluate(EvaluationContext context) throws EvaluationException {
75-
ExpressionResult leftValue = left.evaluate(context);
76-
ExpressionResult rightValue = right.evaluate(context);
74+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) throws EvaluationException {
75+
ExpressionResult leftValue = left.evaluate(context, isObjectValue);
76+
ExpressionResult rightValue = right.evaluate(context, isObjectValue);
7777
if ((leftValue == null || rightValue == null) &&
7878
(operator != Operator.EQUALS && operator != Operator.NOT_EQUALS)) {
7979
throw new EvaluationException("Null inputs for " + operator + " operation: " + leftValue

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/ConditionalExpressionNode.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,14 @@ public ConditionalExpressionNode(ExpressionNode condition, ExpressionNode trueEx
3838
}
3939

4040
@Override
41-
public ExpressionResult evaluate(EvaluationContext context) {
42-
ExpressionResult conditionResult = condition.evaluate(context);
41+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) throws EvaluationException {
42+
ExpressionResult conditionResult = condition.evaluate(context, isObjectValue);
4343
if (conditionResult == null || conditionResult.isNull()) {
4444
throw new EvaluationException("Condition is null in conditional expression");
4545
}
4646
if (conditionResult.isBoolean()) {
47-
return conditionResult.asBoolean() ? trueExpression.evaluate(context) : falseExpression.evaluate(context);
47+
return conditionResult.asBoolean() ? trueExpression.evaluate(context, isObjectValue)
48+
: falseExpression.evaluate(context, isObjectValue);
4849
} else {
4950
throw new EvaluationException("Condition is not a boolean in conditional expression");
5051
}

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/ExpressionNode.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@
2525
* Represents a node in the AST.
2626
*/
2727
public interface ExpressionNode {
28-
ExpressionResult evaluate(EvaluationContext context) throws EvaluationException;
28+
ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) throws EvaluationException;
2929
}

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/ExpressionResult.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
import com.google.gson.JsonSyntaxException;
2828
import com.google.gson.internal.LazilyParsedNumber;
2929
import org.apache.axiom.om.OMElement;
30+
import org.apache.axiom.om.OMNode;
3031
import org.apache.synapse.util.synapse.expression.exception.EvaluationException;
3132

33+
import java.util.List;
34+
3235
/**
3336
* This class represents the result of an expression evaluation.
3437
* It can hold values of different types such as String, Number, Boolean, JsonElement, and null.
@@ -44,7 +47,11 @@ public ExpressionResult(String value) {
4447
this.value = value;
4548
}
4649

47-
public ExpressionResult(OMElement value) {
50+
public ExpressionResult(OMNode value) {
51+
this.value = value;
52+
}
53+
54+
public ExpressionResult(List value) {
4855
this.value = value;
4956
}
5057

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/FilterExpressionNode.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ public FilterExpressionNode(String expression, Map<String, ExpressionNode> argum
4141
* Not evaluating here.
4242
*/
4343
@Override
44-
public ExpressionResult evaluate(EvaluationContext context) {
44+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) {
4545
for (Map.Entry<String, ExpressionNode> entry : arguments.entrySet()) {
4646
if (entry.getValue() != null) {
47-
ExpressionResult result = entry.getValue().evaluate(context);
47+
ExpressionResult result = entry.getValue().evaluate(context, isObjectValue);
4848
if (result != null) {
4949
String regex = ExpressionUtils.escapeSpecialCharacters(entry.getKey());
5050
String resultString = result.asString();

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/HeadersAndPropertiesAccessNode.java

+10-5
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ public enum Type {
3434
HEADER,
3535
PROPERTY,
3636
CONFIG,
37-
QUERY_PARAM,
38-
PATH_PARAM
37+
FUNCTION_PARAM
3938
}
4039

4140
private final Type type;
@@ -56,9 +55,9 @@ public HeadersAndPropertiesAccessNode(ExpressionNode node, String scope) {
5655
}
5756

5857
@Override
59-
public ExpressionResult evaluate(EvaluationContext context) {
58+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) throws EvaluationException {
6059
if (key != null) {
61-
String name = key.evaluate(context).asString();
60+
String name = key.evaluate(context, isObjectValue).asString();
6261
Object value;
6362
if (Type.HEADER.equals(type)) {
6463
value = context.getHeader(name);
@@ -68,6 +67,8 @@ public ExpressionResult evaluate(EvaluationContext context) {
6867
} catch (ResolverException e) {
6968
throw new EvaluationException("The value of the key:[" + name + "] is null");
7069
}
70+
} else if (Type.FUNCTION_PARAM.equals(type)) {
71+
value = context.getFunctionParam(name);
7172
} else {
7273
if (SynapseConstants.URI_PARAM.equals(scope)) {
7374
value = context.getProperty("uri.var." + name, SynapseConstants.SYNAPSE);
@@ -77,7 +78,11 @@ public ExpressionResult evaluate(EvaluationContext context) {
7778
value = context.getProperty(name, scope);
7879
}
7980
}
80-
return new ExpressionResult(value != null ? value.toString() : null);
81+
if (value != null) {
82+
return new ExpressionResult(value.toString());
83+
} else {
84+
throw new EvaluationException("Could not fetch the value of the key: " + name);
85+
}
8186
}
8287
throw new EvaluationException("Key cannot be null when accessing headers or properties");
8388
}

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/LiteralNode.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public LiteralNode(ArgumentListNode value, Type type) {
5050
}
5151

5252
@Override
53-
public ExpressionResult evaluate(EvaluationContext context) {
53+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) {
5454
switch (type) {
5555
case NUMBER:
5656
return parseNumber(value);
@@ -61,7 +61,7 @@ public ExpressionResult evaluate(EvaluationContext context) {
6161
case NULL:
6262
return null;
6363
case ARRAY:
64-
return parseArray(context);
64+
return parseArray(context, isObjectValue);
6565
default:
6666
throw new IllegalArgumentException("Unsupported type: " + type);
6767
}
@@ -83,10 +83,10 @@ private ExpressionResult parseNumber(String value) {
8383
}
8484
}
8585

86-
private ExpressionResult parseArray(EvaluationContext context) {
86+
private ExpressionResult parseArray(EvaluationContext context, boolean isObjectValue) {
8787
JsonArray jsonArray = new JsonArray();
8888
for (ExpressionNode expressionNode : parameterList.getArguments()) {
89-
ExpressionResult result = expressionNode.evaluate(context);
89+
ExpressionResult result = expressionNode.evaluate(context, isObjectValue);
9090
if (result.getType().equals(JsonElement.class)) {
9191
jsonArray.add(result.asJsonElement());
9292
} else if (result.isInteger()) {

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/PayloadAccessNode.java

+24-7
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@
3838
import org.apache.synapse.util.synapse.expression.context.EvaluationContext;
3939
import org.apache.synapse.util.synapse.expression.exception.EvaluationException;
4040
import org.apache.synapse.util.synapse.expression.utils.ExpressionUtils;
41+
import org.jaxen.JaxenException;
4142

4243
import java.io.IOException;
4344
import java.util.EnumSet;
45+
import java.util.List;
4446
import java.util.Map;
4547
import java.util.Optional;
4648
import java.util.Set;
@@ -90,32 +92,47 @@ public Set<Option> options() {
9092
}
9193

9294
@Override
93-
public ExpressionResult evaluate(EvaluationContext context) {
95+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) throws EvaluationException {
9496
if (expression.startsWith(SynapseConstants.PAYLOAD)) {
9597
expression = SynapseConstants.PAYLOAD_$ + expression.substring(SynapseConstants.PAYLOAD.length());
9698
}
9799

98100
for (Map.Entry<String, ExpressionNode> entry : arguments.entrySet()) {
99101
Optional.ofNullable(entry.getValue())
100-
.map(value -> value.evaluate(context))
102+
.map(value -> value.evaluate(context, isObjectValue))
101103
.ifPresent(result -> processResult(entry, result));
102104
}
103105

104-
Object result = null;
106+
Object result;
105107
switch (type) {
106108
case PAYLOAD:
107109
try {
108-
result = context.getPayload();
110+
result = context.getPayload(isObjectValue);
109111
if (result == null) {
110112
throw new EvaluationException("Could not find a JSON payload to evaluate the expression: "
111113
+ expression);
112114
}
113-
result = JsonPath.parse(context.getPayload().toString()).read(expression);
115+
if (context.isJSON()) {
116+
result = JsonPath.parse(result.toString()).read(expression);
117+
} else {
118+
if (expression.equals(SynapseConstants.PAYLOAD_$)) {
119+
// we only get a list result in XPATH evaluation
120+
if (isObjectValue && result instanceof List) {
121+
return new ExpressionResult((List) result);
122+
} else {
123+
return new ExpressionResult(result.toString());
124+
}
125+
}
126+
throw new EvaluationException("Could not evaluate JSONPath expression: " + expression
127+
+ " on non-JSON payload");
128+
}
114129
} catch (PathNotFoundException e) {
115130
// convert jsonPath error to native one
116131
throw new EvaluationException(e.getMessage());
117132
} catch (IOException e) {
118133
throw new EvaluationException("Error while parsing payload");
134+
} catch (JaxenException e) {
135+
throw new EvaluationException("Error while retrieving payload");
119136
}
120137
break;
121138
case VARIABLE:
@@ -140,7 +157,7 @@ public ExpressionResult evaluate(EvaluationContext context) {
140157
}
141158
break;
142159
case REGISTRY:
143-
ExpressionResult registryValue = predefinedFunctionNode.evaluate(context);
160+
ExpressionResult registryValue = predefinedFunctionNode.evaluate(context, isObjectValue);
144161
try {
145162
if (registryValue == null) {
146163
throw new EvaluationException("Could not find a JSON payload to evaluate the expression: " + expression);
@@ -158,7 +175,7 @@ public ExpressionResult evaluate(EvaluationContext context) {
158175
case ARRAY:
159176
case OBJECT:
160177
expression = expression.startsWith(".") ? "$" + expression : "$." + expression;
161-
ExpressionResult objFuncResult = predefinedFunctionNode.evaluate(context);
178+
ExpressionResult objFuncResult = predefinedFunctionNode.evaluate(context, isObjectValue);
162179
try {
163180
result = JsonPath.parse(objFuncResult.asJsonElement()).read(expression);
164181
} catch (PathNotFoundException e) {

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/PredefinedFunctionNode.java

+27-19
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import com.google.gson.JsonArray;
2121
import com.google.gson.JsonPrimitive;
22+
import org.apache.axiom.om.OMNode;
2223
import org.apache.synapse.SynapseConstants;
2324
import org.apache.synapse.util.synapse.expression.context.EvaluationContext;
2425
import org.apache.synapse.util.synapse.expression.exception.EvaluationException;
@@ -54,15 +55,15 @@ public PredefinedFunctionNode(ArgumentListNode arguments, String functionName) {
5455
}
5556

5657
@Override
57-
public ExpressionResult evaluate(EvaluationContext context) {
58+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) {
5859
if (arguments.isEmpty()) {
5960
return handleNoArgumentFunctions();
6061
} else if (arguments.size() == 1) {
61-
return handleSingleArgumentFunctions(context);
62+
return handleSingleArgumentFunctions(context, isObjectValue);
6263
} else if (arguments.size() == 2) {
63-
return handleDoubleArgumentFunctions(context);
64+
return handleDoubleArgumentFunctions(context, isObjectValue);
6465
} else if (arguments.size() == 3) {
65-
return handleTripleArgumentFunctions(context);
66+
return handleTripleArgumentFunctions(context, isObjectValue);
6667
}
6768
throw new EvaluationException("Invalid number of arguments: " + arguments.size()
6869
+ " provided for the function: " + functionName);
@@ -75,11 +76,11 @@ private ExpressionResult handleNoArgumentFunctions() {
7576
throw new EvaluationException("Invalid function: " + functionName + " with no arguments");
7677
}
7778

78-
private ExpressionResult handleSingleArgumentFunctions(EvaluationContext context) {
79+
private ExpressionResult handleSingleArgumentFunctions(EvaluationContext context, boolean isObjectValue) {
7980
ExpressionResult result = null;
8081
// do not evaluate the source for exists function - since we need to catch the exception
8182
if (!functionName.equals(SynapseConstants.EXISTS)) {
82-
result = arguments.get(0).evaluate(context);
83+
result = arguments.get(0).evaluate(context, isObjectValue);
8384
checkArguments(result, "source");
8485
}
8586
switch (functionName) {
@@ -128,13 +129,13 @@ private ExpressionResult handleSingleArgumentFunctions(EvaluationContext context
128129
case SynapseConstants.REGISTRY:
129130
return handleRegistryAccess(context, result, null);
130131
case SynapseConstants.EXISTS:
131-
return handleExistsCheck(context, arguments.get(0));
132+
return handleExistsCheck(context, arguments.get(0), isObjectValue);
132133
case SynapseConstants.OBJECT:
133134
return convertToObject(result);
134135
case SynapseConstants.ARRAY:
135136
return convertToArray(result);
136137
case SynapseConstants.XPATH:
137-
return evaluateXPATHExpression(context, result);
138+
return evaluateXPATHExpression(context, result, isObjectValue);
138139
case SynapseConstants.SECRET:
139140
return fetchSecretValue(context, result.asString());
140141
case SynapseConstants.NOT:
@@ -144,9 +145,9 @@ private ExpressionResult handleSingleArgumentFunctions(EvaluationContext context
144145
}
145146
}
146147

147-
private ExpressionResult handleDoubleArgumentFunctions(EvaluationContext context) {
148-
ExpressionResult source = arguments.get(0).evaluate(context);
149-
ExpressionResult argument1 = arguments.get(1).evaluate(context);
148+
private ExpressionResult handleDoubleArgumentFunctions(EvaluationContext context, boolean isObjectValue) {
149+
ExpressionResult source = arguments.get(0).evaluate(context, isObjectValue);
150+
ExpressionResult argument1 = arguments.get(1).evaluate(context, isObjectValue);
150151
checkArguments(source, "source");
151152
checkArguments(argument1, "argument1");
152153
switch (functionName) {
@@ -179,10 +180,10 @@ private ExpressionResult handleDoubleArgumentFunctions(EvaluationContext context
179180
}
180181
}
181182

182-
private ExpressionResult handleTripleArgumentFunctions(EvaluationContext context) {
183-
ExpressionResult source = arguments.get(0).evaluate(context);
184-
ExpressionResult argument1 = arguments.get(1).evaluate(context);
185-
ExpressionResult argument2 = arguments.get(2).evaluate(context);
183+
private ExpressionResult handleTripleArgumentFunctions(EvaluationContext context, boolean isObjectValue) {
184+
ExpressionResult source = arguments.get(0).evaluate(context, isObjectValue);
185+
ExpressionResult argument1 = arguments.get(1).evaluate(context, isObjectValue);
186+
ExpressionResult argument2 = arguments.get(2).evaluate(context, isObjectValue);
186187
checkArguments(source, "source");
187188
checkArguments(argument1, "argument1");
188189
checkArguments(argument2, "argument2");
@@ -573,9 +574,10 @@ private ExpressionResult handleRegistryAccess(EvaluationContext ctx, ExpressionR
573574
+ ", propKey: " + propKey.asString());
574575
}
575576

576-
private ExpressionResult handleExistsCheck(EvaluationContext context, ExpressionNode expression) {
577+
private ExpressionResult handleExistsCheck(EvaluationContext context, ExpressionNode expression,
578+
boolean isObjectValue) {
577579
try {
578-
ExpressionResult result = expression.evaluate(context);
580+
ExpressionResult result = expression.evaluate(context, isObjectValue);
579581
return result != null ? new ExpressionResult(true) : new ExpressionResult(false);
580582
} catch (EvaluationException e) {
581583
// this is the only method we are handling the exceptions
@@ -597,9 +599,15 @@ private ExpressionResult convertToArray(ExpressionResult result) {
597599
throw new EvaluationException("Argument cannot be converted to a JSON array");
598600
}
599601

600-
private ExpressionResult evaluateXPATHExpression(EvaluationContext context, ExpressionResult expression) {
602+
private ExpressionResult evaluateXPATHExpression(EvaluationContext context, ExpressionResult expression,
603+
boolean isObjectValue) {
601604
try {
602-
return new ExpressionResult(context.evaluateXpathExpression(expression.asString()));
605+
Object result = context.evaluateXpathExpression(expression.asString(), isObjectValue);
606+
if (isObjectValue) {
607+
return new ExpressionResult((List<?>) result);
608+
} else {
609+
return new ExpressionResult(result.toString());
610+
}
603611
} catch (JaxenException e) {
604612
throw new EvaluationException("Invalid XPATH expression : " + expression.asString());
605613
}

modules/core/src/main/java/org/apache/synapse/util/synapse/expression/ast/SignedExpressionNode.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public SignedExpressionNode(ExpressionNode expression, boolean signed) {
3636
}
3737

3838
@Override
39-
public ExpressionResult evaluate(EvaluationContext context) {
40-
ExpressionResult result = expression.evaluate(context);
39+
public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValue) {
40+
ExpressionResult result = expression.evaluate(context, isObjectValue);
4141
if (result == null || result.isNull()) {
4242
throw new IllegalStateException("Cannot negate a null value");
4343
}

0 commit comments

Comments
 (0)