Skip to content

Commit c3515a4

Browse files
Merge pull request #2227 from GDLMadushanka/SIEL
Introduce Synapse Expression support
2 parents 3f7d461 + c49288d commit c3515a4

38 files changed

+4337
-9
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
target/
1616

1717
## various other file types we don't want to have in the repository:
18-
.DS_Store
18+
.DS_Store
19+
/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/gen/

modules/core/pom.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,44 @@
145145
</execution>
146146
</executions>
147147
</plugin>
148+
<plugin>
149+
<groupId>org.antlr</groupId>
150+
<artifactId>antlr4-maven-plugin</artifactId>
151+
<executions>
152+
<execution>
153+
<id>antlr</id>
154+
<phase>generate-sources</phase>
155+
<goals>
156+
<goal>antlr4</goal>
157+
</goals>
158+
<configuration>
159+
<sourceDirectory>${project.basedir}/src/main/antlr4</sourceDirectory>
160+
<arguments>
161+
<argument>-visitor</argument>
162+
</arguments>
163+
</configuration>
164+
</execution>
165+
</executions>
166+
</plugin>
167+
<!-- Build Helper Maven Plugin -->
168+
<plugin>
169+
<groupId>org.codehaus.mojo</groupId>
170+
<artifactId>build-helper-maven-plugin</artifactId>
171+
<executions>
172+
<execution>
173+
<id>add-source</id>
174+
<phase>generate-sources</phase>
175+
<goals>
176+
<goal>add-source</goal>
177+
</goals>
178+
<configuration>
179+
<sources>
180+
<source>${project.build.directory}/generated-sources/antlr4</source>
181+
</sources>
182+
</configuration>
183+
</execution>
184+
</executions>
185+
</plugin>
148186

149187
<!-- Attach a JAR with the test classes so that we can reuse them in other
150188
modules (see http://maven.apache.org/guides/mini/guide-attached-tests.html). -->
@@ -506,5 +544,9 @@
506544
<groupId>org.apache.logging.log4j</groupId>
507545
<artifactId>log4j-slf4j-impl</artifactId>
508546
</dependency>
547+
<dependency>
548+
<groupId>org.antlr</groupId>
549+
<artifactId>antlr4-runtime</artifactId>
550+
</dependency>
509551
</dependencies>
510552
</project>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
lexer grammar ExpressionLexer;
2+
3+
JSONPATH_PARAMS: 'in' | 'nin' | 'subsetof' | 'anyof' | 'noneof' | 'size' | 'empty' | '=~';
4+
5+
JSONPATH_FUNCTIONS: 'length()' | 'size()' | 'min()' | 'max()' | 'avg()' | 'sum()' | 'stddev()' | 'keys()' | 'first()' | 'last()';
6+
7+
// Tokens for identifiers, operators, and keywords
8+
VAR: 'var';
9+
PAYLOAD: 'payload' | '$';
10+
HEADERS: 'headers';
11+
CONFIG: 'config';
12+
ATTRIBUTES: 'attributes' | 'attr';
13+
AND: 'and' | '&&';
14+
OR: 'or' | '||';
15+
NOT: '!';
16+
17+
DOUBLE_DOT : '..';
18+
ASTERISK : '*';
19+
20+
// Operators
21+
PLUS: '+';
22+
MINUS: '-';
23+
DIV: '/';
24+
MODULO: '%';
25+
EQ: '==';
26+
NEQ: '!=';
27+
GT: '>';
28+
LT: '<';
29+
GTE: '>=';
30+
LTE: '<=';
31+
32+
// Delimiters
33+
LPAREN: '(';
34+
RPAREN: ')';
35+
LBRACKET: '[';
36+
RBRACKET: ']';
37+
DOT: '.';
38+
COMMA: ',';
39+
COLON: ':';
40+
QUOTE: '"' | '\'';
41+
42+
// Literals
43+
BOOLEAN_LITERAL: 'true' | 'false';
44+
NUMBER: '-'? [0-9]+ ('.' [0-9]+)?;
45+
46+
47+
STRING_LITERAL : ('"' (ESC | ~["\\])* '"' | '\'' (ESC | ~['\\])* '\'');
48+
49+
50+
fragment ESC
51+
: '\\' [btnfr"'\\/] // Basic escape sequences
52+
| UNICODE_ESC
53+
| OCTAL_ESC
54+
;
55+
56+
fragment UNICODE_ESC
57+
: '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
58+
;
59+
60+
fragment OCTAL_ESC
61+
: '\\' [0-3]? [0-7] [0-7]
62+
;
63+
64+
fragment HEX_DIGIT
65+
: [0-9a-fA-F]
66+
;
67+
68+
NULL_LITERAL
69+
: 'null' // Define null as a recognized keyword
70+
;
71+
72+
// Identifiers
73+
ID: [a-zA-Z_][a-zA-Z_0-9]*;
74+
75+
// Special symbols for JSONPath filter expressions
76+
QUESTION: '?';
77+
AT: '@';
78+
79+
// Whitespace
80+
WS: [ \t\n\r]+ -> skip;
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
parser grammar ExpressionParser;
2+
3+
options {
4+
tokenVocab = ExpressionLexer;
5+
}
6+
7+
expression
8+
: comparisonExpression
9+
| conditionalExpression
10+
| EOF
11+
;
12+
13+
conditionalExpression
14+
: comparisonExpression (QUESTION expression COLON expression)?
15+
;
16+
17+
comparisonExpression
18+
: logicalExpression ( (GT | LT | GTE | LTE | EQ | NEQ) logicalExpression )*
19+
| logicalExpression (EQ | NEQ) NULL_LITERAL
20+
;
21+
22+
logicalExpression
23+
: arithmeticExpression (AND logicalExpression | OR logicalExpression)?
24+
;
25+
26+
arithmeticExpression
27+
: term ( (PLUS | MINUS) term )*
28+
;
29+
30+
term
31+
: factor ( (ASTERISK | DIV | MODULO) factor )*
32+
;
33+
34+
factor
35+
: literal
36+
| functionCall
37+
| variableAccess
38+
| payloadAccess
39+
| headerAccess
40+
| configAccess
41+
| attributeAccess
42+
| LPAREN expression RPAREN
43+
;
44+
45+
configAccess
46+
: CONFIG propertyName
47+
;
48+
49+
headerAccess
50+
: HEADERS propertyName
51+
;
52+
53+
attributeAccess
54+
: ATTRIBUTES (DOT ID propertyName)
55+
;
56+
57+
propertyName
58+
: DOT ID
59+
| (DOT)? LBRACKET STRING_LITERAL RBRACKET
60+
;
61+
62+
literal
63+
: arrayLiteral
64+
| BOOLEAN_LITERAL
65+
| NUMBER
66+
| STRING_LITERAL
67+
| NULL_LITERAL
68+
;
69+
70+
jsonPathExpression
71+
:( DOT JSONPATH_FUNCTIONS
72+
|DOUBLE_DOT ASTERISK
73+
| DOUBLE_DOT ID
74+
| DOT ID
75+
| (DOT)? LBRACKET arrayIndex RBRACKET
76+
| DOT ASTERISK
77+
| DOUBLE_DOT ID (LBRACKET arrayIndex RBRACKET)?)+
78+
;
79+
80+
81+
variableAccess
82+
: VAR ( DOT ID
83+
| DOT STRING_LITERAL
84+
| (DOT)? LBRACKET STRING_LITERAL RBRACKET // Bracket notation: var["variableName"]
85+
)
86+
( jsonPathExpression )?
87+
;
88+
89+
arrayLiteral
90+
: LBRACKET (expression (COMMA expression)*)? RBRACKET // Array with zero or more literals, separated by commas
91+
;
92+
93+
payloadAccess
94+
: PAYLOAD ( jsonPathExpression)?
95+
;
96+
97+
arrayIndex
98+
: NUMBER
99+
| STRING_LITERAL
100+
| expression
101+
| multipleArrayIndices
102+
| sliceArrayIndex
103+
| expression ( (PLUS | MINUS | ASTERISK | DIV ) expression)*
104+
| ASTERISK
105+
| QUESTION? filterExpression
106+
;
107+
108+
multipleArrayIndices
109+
: expression (COMMA expression)+
110+
;
111+
112+
sliceArrayIndex
113+
: signedExpressions? COLON signedExpressions? (COLON signedExpressions?)?
114+
;
115+
116+
signedExpressions
117+
: MINUS? expression
118+
;
119+
120+
filterExpression
121+
: (filterComponent)+
122+
;
123+
124+
filterComponent
125+
: variableAccess
126+
| payloadAccess
127+
| headerAccess
128+
| configAccess
129+
| attributeAccess
130+
| functionCall
131+
| stringOrOperator
132+
;
133+
134+
stringOrOperator
135+
: QUESTION | AT | JSONPATH_PARAMS | STRING_LITERAL |NUMBER | BOOLEAN_LITERAL | ID | GT | LT | GTE | LTE | EQ | NEQ
136+
| PLUS | MINUS | DIV | LPAREN | RPAREN | DOT | COMMA | COLON | WS | AND | OR | NOT | ASTERISK
137+
;
138+
139+
140+
functionCall
141+
: ID LPAREN (expression (COMMA expression)*)? RPAREN functionCallSuffix?
142+
;
143+
144+
functionCallSuffix
145+
: DOT ID LPAREN (expression (COMMA expression)*)? RPAREN // Method chaining
146+
| jsonPathExpression
147+
;

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,4 +625,57 @@ public enum ENDPOINT_TIMEOUT_TYPE { ENDPOINT_TIMEOUT, GLOBAL_TIMEOUT, HTTP_CONNE
625625
public static final String JAEGER_SPAN_ID = "jaeger_span_id";
626626

627627
public static final String ANALYTICS_METADATA = "ANALYTICS_METADATA";
628+
629+
// Constants related to Synapse Expressions
630+
public static final String AND = "and";
631+
public static final String OR = "or";
632+
public static final String NOT = "not";
633+
public static final String TO_LOWER = "toLower";
634+
public static final String TO_UPPER = "toUpper";
635+
public static final String LENGTH = "length";
636+
public static final String SUBSTRING = "subString";
637+
public static final String STARTS_WITH = "startsWith";
638+
public static final String ENDS_WITH = "endsWith";
639+
public static final String CONTAINS = "contains";
640+
public static final String TRIM = "trim";
641+
public static final String REPLACE = "replace";
642+
public static final String SPLIT = "split";
643+
public static final String NOW = "now";
644+
public static final String ABS = "abs";
645+
public static final String CEIL = "ceil";
646+
public static final String FLOOR = "floor";
647+
public static final String SQRT = "sqrt";
648+
public static final String LOG = "log";
649+
public static final String POW = "pow";
650+
public static final String B64ENCODE = "base64encode";
651+
public static final String B64DECODE = "base64decode";
652+
public static final String URL_ENCODE = "urlEncode";
653+
public static final String URL_DECODE = "urlDecode";
654+
public static final String IS_NUMBER = "isNumber";
655+
public static final String IS_STRING = "isString";
656+
public static final String IS_ARRAY = "isArray";
657+
public static final String IS_OBJECT = "isObject";
658+
public static final String OBJECT = "object";
659+
public static final String ARRAY = "array";
660+
public static final String REGISTRY = "registry";
661+
public static final String EXISTS = "exists";
662+
public static final String XPATH = "xpath";
663+
public static final String SECRET = "secret";
664+
665+
public static final String ROUND = "round";
666+
public static final String INTEGER = "integer";
667+
public static final String FLOAT = "float";
668+
public static final String STRING = "string";
669+
public static final String BOOLEAN = "boolean";
670+
671+
public static final String PAYLOAD = "payload";
672+
public static final String PAYLOAD_$ = "$";
673+
public static final String SYNAPSE_EXPRESSION_IDENTIFIER_START = "${";
674+
public static final String SYNAPSE_EXPRESSION_IDENTIFIER_END = "}";
675+
public static final String AXIS2 = "axis2";
676+
public static final String QUERY_PARAM = "queryParams";
677+
public static final String URI_PARAM = "uriParams";
678+
679+
public static final String UNKNOWN = "unknown";
680+
public static final String VAULT_LOOKUP = "wso2:vault-lookup('";
628681
}

modules/core/src/main/java/org/apache/synapse/config/xml/PropertyMediatorFactory.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
import org.apache.axiom.om.OMAttribute;
2323
import org.apache.axiom.om.OMElement;
2424
import org.apache.synapse.Mediator;
25+
import org.apache.synapse.SynapseConstants;
2526
import org.apache.synapse.SynapseException;
2627
import org.apache.synapse.mediators.Value;
2728
import org.apache.synapse.mediators.builtin.PropertyMediator;
2829
import org.apache.synapse.util.MediatorPropertyUtils;
2930
import org.apache.synapse.util.xpath.SynapseJsonPath;
31+
import org.apache.synapse.util.xpath.SynapseExpression;
3032
import org.apache.synapse.util.xpath.SynapseXPath;
3133
import org.jaxen.JaxenException;
3234

@@ -83,6 +85,9 @@ public Mediator createSpecificMediator(OMElement elem, Properties properties) {
8385
String nameExpression = nameAttributeValue.substring(1, nameAttributeValue.length() - 1);
8486
if(nameExpression.startsWith("json-eval(")) {
8587
new SynapseJsonPath(nameExpression.substring(10, nameExpression.length() - 1));
88+
} else if (nameExpression.startsWith(SynapseConstants.SYNAPSE_EXPRESSION_IDENTIFIER_START) &&
89+
nameExpression.endsWith(SynapseConstants.SYNAPSE_EXPRESSION_IDENTIFIER_END)) {
90+
new SynapseExpression(nameExpression.substring(2, nameExpression.length() - 1));
8691
} else {
8792
new SynapseXPath(nameExpression);
8893
}

0 commit comments

Comments
 (0)