diff --git a/.gitignore b/.gitignore index 96689a4935..ec32ace4b0 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ target/ ## various other file types we don't want to have in the repository: -.DS_Store \ No newline at end of file +.DS_Store +/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/gen/ diff --git a/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/ExpressionLexer.g4 b/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/ExpressionLexer.g4 index 072f463914..1fd3f8b3e7 100644 --- a/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/ExpressionLexer.g4 +++ b/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/ExpressionLexer.g4 @@ -7,7 +7,7 @@ VAR: 'var'; PAYLOAD: 'payload' | '$'; HEADERS: 'headers'; CONFIG: 'config'; -ATTRIBUTES: 'attributes'; +ATTRIBUTES: 'attributes' | 'attr'; AXIS2: 'axis2'; SYNAPSE: 'synapse'; REGISTRY: 'registry'; @@ -28,6 +28,8 @@ INTEGER: 'integer'; FLOAT: 'float'; STRING: 'string'; BOOLEAN: 'boolean'; +OBJECT: 'object'; +ARRAY: 'array'; ABS: 'abs'; FLOOR: 'floor'; CEIL: 'ceil'; @@ -41,6 +43,7 @@ SUBSTRING: 'subString'; STARTSWITH: 'startsWith'; ENDSWITH: 'endsWith'; CONTAINS: 'contains'; +EXISTS: 'exists'; TRIM: 'trim'; REPLACE: 'replace'; SPLIT: 'split'; @@ -104,8 +107,8 @@ NULL_LITERAL ; // Identifiers -ID: [a-zA-Z_][a-zA-Z_0-9]*; GETPROPERTY: 'getProperty'; +ID: [a-zA-Z_][a-zA-Z_0-9]*; // Special symbols for JSONPath filter expressions QUESTION: '?'; AT: '@'; diff --git a/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/ExpressionParser.g4 b/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/ExpressionParser.g4 index 5f72f75261..72ce8693f5 100644 --- a/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/ExpressionParser.g4 +++ b/modules/core/src/main/antlr4/org/apache/synapse/util/synapse_path/ExpressionParser.g4 @@ -100,6 +100,15 @@ payloadAccess | DOUBLE_DOT ID (LBRACKET arrayIndex RBRACKET)? ) ; +registryAccess + : (DOUBLE_DOT ASTERISK + | DOUBLE_DOT ID + | DOT ID + | LBRACKET arrayIndex RBRACKET + | DOT LBRACKET arrayIndex RBRACKET + | DOT ASTERISK)* + ; + arrayIndex : NUMBER | STRING_LITERAL @@ -161,7 +170,7 @@ functionCall | SQRT LPAREN expression RPAREN | LOG LPAREN expression RPAREN | POW LPAREN expression COMMA expression RPAREN - | REGISTRY LPAREN expression RPAREN (DOT GETPROPERTY LPAREN expression RPAREN)? + | REGISTRY LPAREN expression RPAREN ( (DOT GETPROPERTY LPAREN expression RPAREN) | registryAccess )? | SECRET LPAREN expression RPAREN | BASE64ENCODE LPAREN expression (COMMA expression)? RPAREN | BASE64DECODE LPAREN expression RPAREN @@ -179,4 +188,7 @@ functionCall | FLOAT LPAREN expression RPAREN | STRING LPAREN expression RPAREN | BOOLEAN LPAREN expression RPAREN + | EXISTS LPAREN expression RPAREN + | OBJECT LPAREN expression RPAREN + | ARRAY LPAREN expression RPAREN ; diff --git a/modules/core/src/main/java/org/apache/synapse/SynapseConstants.java b/modules/core/src/main/java/org/apache/synapse/SynapseConstants.java index e4e987f8ef..38ddb7d615 100644 --- a/modules/core/src/main/java/org/apache/synapse/SynapseConstants.java +++ b/modules/core/src/main/java/org/apache/synapse/SynapseConstants.java @@ -655,6 +655,10 @@ public enum ENDPOINT_TIMEOUT_TYPE { ENDPOINT_TIMEOUT, GLOBAL_TIMEOUT, HTTP_CONNE public static final String IS_STRING = "isString"; public static final String IS_ARRAY = "isArray"; public static final String IS_OBJECT = "isObject"; + public static final String OBJECT = "object"; + public static final String ARRAY = "array"; + public static final String REGISTRY = "registry"; + public static final String EXISTS = "exists"; public static final String ROUND = "round"; public static final String INTEGER = "integer"; @@ -669,16 +673,4 @@ public enum ENDPOINT_TIMEOUT_TYPE { ENDPOINT_TIMEOUT, GLOBAL_TIMEOUT, HTTP_CONNE public static final String AXIS2 = "axis2"; public static final String UNKNOWN = "unknown"; - - public static final class SIELErrors { - public static final String IF_CONDITION_ERROR = "Condition is not a boolean value"; - private static final String INVALID_ARGUMENT = "Invalid argument type provided for %s function"; - private static final String INVALID_OPERATION = "Invalid argument type provided for %s operation"; - public static String getInvalidArgumentMessage(String functionName) { - return String.format(INVALID_ARGUMENT, functionName); - } - public static String getInvalidOperationMessage(String functionName) { - return String.format(INVALID_OPERATION, functionName); - } - } } diff --git a/modules/core/src/main/java/org/apache/synapse/config/xml/PropertyMediatorFactory.java b/modules/core/src/main/java/org/apache/synapse/config/xml/PropertyMediatorFactory.java index abea2741ae..952c8abfde 100644 --- a/modules/core/src/main/java/org/apache/synapse/config/xml/PropertyMediatorFactory.java +++ b/modules/core/src/main/java/org/apache/synapse/config/xml/PropertyMediatorFactory.java @@ -28,7 +28,7 @@ import org.apache.synapse.mediators.builtin.PropertyMediator; import org.apache.synapse.util.MediatorPropertyUtils; import org.apache.synapse.util.xpath.SynapseJsonPath; -import org.apache.synapse.util.xpath.SynapsePath; +import org.apache.synapse.util.xpath.Synapse_Path; import org.apache.synapse.util.xpath.SynapseXPath; import org.jaxen.JaxenException; @@ -87,7 +87,7 @@ public Mediator createSpecificMediator(OMElement elem, Properties properties) { new SynapseJsonPath(nameExpression.substring(10, nameExpression.length() - 1)); } else if (nameExpression.startsWith(SynapseConstants.SIEL_IDENTIFIER_START) && nameExpression.endsWith(SynapseConstants.SIEL_IDENTIFIER_END)) { - new SynapsePath(nameExpression.substring(2, nameExpression.length() - 1)); + new Synapse_Path(nameExpression.substring(2, nameExpression.length() - 1)); } else { new SynapseXPath(nameExpression); } diff --git a/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePath.java b/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePath.java index 77b2c1a650..c66d4eb27f 100644 --- a/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePath.java +++ b/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePath.java @@ -106,6 +106,13 @@ public String toString() { public abstract String stringValueOf(MessageContext synCtx); + /** + * New method to get the object value of the expression in places where we can handle the Object result. + * @param synCtx MessageContext + * @return Object - can be String, Integer, Double, Boolean, OMNode, JSONElement or null. + */ + public abstract Object objectValueOf(MessageContext synCtx); + public void handleException(String msg, Throwable e) { log.error(msg, e); throw new SynapseException(msg, e); diff --git a/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePathFactory.java b/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePathFactory.java index 8303492bf9..eccdf91bf1 100644 --- a/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePathFactory.java +++ b/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePathFactory.java @@ -27,7 +27,7 @@ import org.apache.synapse.SynapseException; import org.apache.synapse.config.SynapsePropertiesLoader; import org.apache.synapse.util.xpath.SynapseJsonPath; -import org.apache.synapse.util.xpath.SynapsePath; +import org.apache.synapse.util.xpath.Synapse_Path; import org.apache.synapse.util.xpath.SynapseXPath; import org.jaxen.JaxenException; @@ -52,7 +52,7 @@ public static org.apache.synapse.config.xml.SynapsePath getSynapsePath(OMElement path = new SynapseJsonPath(pathAttrib.getAttributeValue().substring(10, pathAttrib.getAttributeValue().length() - 1)); } else if (pathAttrib.getAttributeValue().startsWith(SynapseConstants.SIEL_IDENTIFIER_START) && pathAttrib.getAttributeValue().endsWith(SynapseConstants.SIEL_IDENTIFIER_END)) { - path = new SynapsePath(pathAttrib.getAttributeValue().substring(2, pathAttrib.getAttributeValue().length() - 1)); + path = new Synapse_Path(pathAttrib.getAttributeValue().substring(2, pathAttrib.getAttributeValue().length() - 1)); } else { try { path = new SynapseXPath(pathAttrib.getAttributeValue()); diff --git a/modules/core/src/main/java/org/apache/synapse/util/synapse_path/ast/ExpressionResult.java b/modules/core/src/main/java/org/apache/synapse/util/synapse_path/ast/ExpressionResult.java index 2957dadd16..7b55156f56 100644 --- a/modules/core/src/main/java/org/apache/synapse/util/synapse_path/ast/ExpressionResult.java +++ b/modules/core/src/main/java/org/apache/synapse/util/synapse_path/ast/ExpressionResult.java @@ -18,10 +18,15 @@ package org.apache.synapse.util.synapse_path.ast; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSyntaxException; import com.google.gson.internal.LazilyParsedNumber; +import org.apache.axiom.om.OMElement; import org.apache.synapse.util.synapse_path.exception.EvaluationException; /** @@ -39,6 +44,14 @@ public ExpressionResult(String value) { this.value = value; } + public ExpressionResult(OMElement value) { + this.value = value; + } + + public Object getValue() { + return value; + } + public ExpressionResult(Number value) { this.value = value; } @@ -119,6 +132,24 @@ public JsonElement asJsonElement() { throw new EvaluationException("Value is not a JsonElement"); } + public JsonObject asJsonObject() { + if (value instanceof JsonObject) { + return (JsonObject) value; + } else if (value instanceof String) { + return parseStringToJsonObject((String) value); + } + throw new EvaluationException("Value is not a JsonObject"); + } + + public JsonArray asJsonArray() { + if (value instanceof JsonArray) { + return (JsonArray) value; + } else if (value instanceof String) { + return parseStringToJsonArray((String) value); + } + throw new EvaluationException("Value is not a JsonArray"); + } + // Method to check the actual type of the result public Class getType() { if (value == null) { @@ -148,11 +179,31 @@ public boolean isString() { } public boolean isObject() { - return value instanceof JsonElement && ((JsonElement) value).isJsonObject(); + if (value instanceof JsonElement && ((JsonElement) value).isJsonObject()) { + return true; + } else if (value instanceof String) { + try { + parseStringToJsonObject((String) value); + return true; + } catch (EvaluationException e) { + return false; + } + } + return false; } public boolean isArray() { - return value instanceof JsonElement && ((JsonElement) value).isJsonArray(); + if (value instanceof JsonElement && ((JsonElement) value).isJsonArray()) { + return true; + } else if (value instanceof String) { + try { + parseStringToJsonArray((String) value); + return true; + } catch (Exception e) { + return false; + } + } + return false; } public boolean isJsonPrimitive() { @@ -197,4 +248,40 @@ private boolean isDouble(JsonPrimitive jsonPrimitive) { } return false; // Not a number, so it's not a double } + + public boolean isOMElement() { + return value instanceof OMElement; + } + + private JsonObject parseStringToJsonObject(String value) throws EvaluationException { + String stringValue = value; + if (stringValue.startsWith("\"") && stringValue.endsWith("\"")) { + stringValue = stringValue.substring(1, stringValue.length() - 1); + } + try { + JsonElement jsonElement = JsonParser.parseString(stringValue.replace("\\", "")); + if (jsonElement.isJsonObject()) { + return jsonElement.getAsJsonObject(); + } + } catch (JsonSyntaxException e) { + throw new EvaluationException("Value is not a JsonObject"); + } + throw new EvaluationException("Value is not a JsonObject"); + } + + private JsonArray parseStringToJsonArray(String value) throws EvaluationException { + String stringValue = value; + if (stringValue.startsWith("\"") && stringValue.endsWith("\"")) { + stringValue = stringValue.substring(1, stringValue.length() - 1); + } + try { + JsonElement jsonElement = JsonParser.parseString(stringValue.replace("\\", "")); + if (jsonElement.isJsonArray()) { + return jsonElement.getAsJsonArray(); + } + } catch (JsonSyntaxException e) { + throw new EvaluationException("Value is not a JsonArray"); + } + throw new EvaluationException("Value is not a JsonArray"); + } } diff --git a/modules/core/src/main/java/org/apache/synapse/util/synapse_path/ast/PayloadAccessNode.java b/modules/core/src/main/java/org/apache/synapse/util/synapse_path/ast/PayloadAccessNode.java index 196f546cb2..8311d2c64d 100644 --- a/modules/core/src/main/java/org/apache/synapse/util/synapse_path/ast/PayloadAccessNode.java +++ b/modules/core/src/main/java/org/apache/synapse/util/synapse_path/ast/PayloadAccessNode.java @@ -53,13 +53,20 @@ public class PayloadAccessNode implements ExpressionNode { private static final Log log = LogFactory.getLog(PayloadAccessNode.class); private String expression; private final Map arguments; + public enum Type { + PAYLOAD, + VARIABLE, + REGISTRY, + } + private final Type type; + private ExpressionNode registryAccessNode = null; - private final boolean isVariable; - - public PayloadAccessNode(String expression, Map arguments, boolean isVariable) { + public PayloadAccessNode(String expression, Map arguments, Type type, + ExpressionNode registryAccessNode) { this.expression = expression; this.arguments = arguments; - this.isVariable = isVariable; + this.type = type; + this.registryAccessNode = registryAccessNode; Configuration.setDefaults(new Configuration.Defaults() { private final JsonProvider jsonProvider = new GsonJsonProvider(new GsonBuilder().serializeNulls().create()); private final MappingProvider mappingProvider = new GsonMappingProvider(); @@ -80,7 +87,7 @@ public Set