Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add variable support for call mediator and improve synapse expression #2250

Merged
merged 5 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,15 @@ private void populateTarget(CallMediator callMediator, Target target, OMElement
}
} else if (target.getTargetType() == EnrichMediator.BODY) {
callMediator.setTargetAvailable(false);
} else if (target.getTargetType() == EnrichMediator.VARIABLE) {
// check if variable is surrounded by curly braces
if (StringUtils.isNotEmpty(sourceEle.getText())) {
callMediator.setTargetAvailable(true);
target.setVariable(new ValueFactory().createTextValue(sourceEle));
} else {
handleException("Variable name is required for VARIABLE type");
}
}

}

public QName getTagQName() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ private OMElement serializeTarget(Target target) {
targetEle.addAttribute(fac.createOMAttribute("type", nullNS, intTypeToString(target.getTargetType())));
if (target.getTargetType() == EnrichMediator.PROPERTY) {
targetEle.setText(target.getProperty());
} else if (target.getTargetType() == EnrichMediator.VARIABLE) {
targetEle.setText(target.getVariable().getKeyValue());
}

return targetEle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ public Value createTextValue(OMElement elem) {
textValue = textValue.substring(1, textValue.length() - 1);
SynapseJsonPath synJsonPath = createSynJsonPath(textValue);
key = new Value(synJsonPath);
} else if (textValue.startsWith("{${") && textValue.endsWith("}}")) {
textValue = textValue.substring(1, textValue.length() - 1);
SynapseExpression synapseExpression = createSynapseExpression(textValue);
key = new Value(synapseExpression);
} else {
SynapseXPath synXpath = createSynXpath(elem, textValue);
key = new Value(synXpath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.apache.synapse.endpoints.EndpointDefinition;
import org.apache.synapse.endpoints.IndirectEndpoint;
import org.apache.synapse.mediators.AbstractMediator;
import org.apache.synapse.mediators.elementary.EnrichMediator;
import org.apache.synapse.mediators.elementary.Source;
import org.apache.synapse.mediators.elementary.Target;
import org.apache.synapse.message.senders.blocking.BlockingMsgSender;
Expand Down Expand Up @@ -167,8 +168,11 @@ public boolean mediate(MessageContext synInCtx) {
sourceForInboundPayload.setClone(true);
CallMediatorEnrichUtil
.doEnrich(synInCtx, sourceForInboundPayload, targetForOriginalPayload, originalMessageType);
CallMediatorEnrichUtil
.doEnrich(synInCtx, sourceForOutboundPayload, targetForOutboundPayload, getSourceMessageType());
if (!(EnrichMediator.BODY == sourceForOutboundPayload.getSourceType() &&
EnrichMediator.BODY == targetForOutboundPayload.getTargetType())) {
CallMediatorEnrichUtil
.doEnrich(synInCtx, sourceForOutboundPayload, targetForOutboundPayload, getSourceMessageType());
}
if (!sourceMessageType.equalsIgnoreCase(originalMessageType)) {
CallMediatorEnrichUtil.setContentType(synInCtx, sourceMessageType, sourceMessageType);
if (originalMessageType.equalsIgnoreCase(JSON_TYPE)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,4 +434,8 @@ public Set<Option> options() {
});
}

public static JsonObject convertMapToJsonObj(Object map) {
return new GsonBuilder().create().toJsonTree(map).getAsJsonObject();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public class EnrichMediator extends AbstractMediator {

public static final int KEY = 5;

public static final int VARIABLE = 6;

private Source source = null;

private Target target = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,29 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.MessageContext;
import org.apache.synapse.SynapseConstants;
import org.apache.synapse.SynapseException;
import org.apache.synapse.SynapseLog;
import org.apache.synapse.commons.json.Constants;
import org.apache.synapse.commons.json.JsonUtil;
import org.apache.synapse.config.xml.SynapsePath;
import org.apache.synapse.config.xml.XMLConfigConstants;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.apache.synapse.mediators.Value;
import org.apache.synapse.mediators.eip.EIPUtils;
import org.apache.synapse.util.CallMediatorEnrichUtil;
import org.apache.synapse.util.InlineExpressionUtil;
import org.apache.synapse.util.synapse.expression.constants.ExpressionConstants;
import org.apache.synapse.util.xpath.SynapseJsonPath;
import org.apache.synapse.util.xpath.SynapseXPath;
import org.apache.synapse.util.xpath.SynapseXPathConstants;
import org.jaxen.JaxenException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -87,6 +93,8 @@ public class Target {

private String property = null;

private Value variable = null;

private int targetType = EnrichMediator.CUSTOM;

public static final String ACTION_REMOVE = "remove";
Expand Down Expand Up @@ -232,6 +240,27 @@ public void insert(MessageContext synContext,
}else{
synContext.setProperty(property, sourceNodeList);
}
} else if (targetType == EnrichMediator.VARIABLE) {
if (action.equalsIgnoreCase(ACTION_REPLACE)) {
String key = variable.evaluateValue(synContext);
if (StringUtils.isEmpty(key)) {
synLog.error("Variable key cannot be null");
throw new SynapseException("Variable key cannot be null");
}
Map<String, Object> result = new HashMap<>();
result.put(ExpressionConstants.PAYLOAD, sourceNodeList);
Map transportHeaders = (Map)((Axis2MessageContext) synContext).getAxis2MessageContext()
.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
JsonObject headers = EIPUtils.convertMapToJsonObj(transportHeaders);
result.put(ExpressionConstants.HEADERS, headers);
result.put(ExpressionConstants.ATTRIBUTES, CallMediatorEnrichUtil.populateTransportAttributes(synContext));
synContext.setVariable(key, result);
} else {
synLog.error("Action " + action + " is not supported when enriching variables");
}
} else {
synLog.error("Invalid Target type");
throw new SynapseException("Invalid Target type");
}
}

Expand Down Expand Up @@ -459,6 +488,23 @@ public void insertJson(MessageContext synCtx, Object sourceJsonElement, SynapseL
}
break;
}
case EnrichMediator.VARIABLE:
if (action.equalsIgnoreCase(ACTION_REPLACE)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get a requirement to enrich to variables in other mediator, this may lead to a conflict. WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are not giving priority to the Enrich mediator going forward, we don't have to consider this.

String key = variable.evaluateValue(synCtx);
if (StringUtils.isEmpty(key)) {
synLog.error("Variable key cannot be null");
return;
}
Map<String, Object> result = new HashMap<>();
result.put(ExpressionConstants.PAYLOAD, sourceJsonElement);
Map transportHeaders = (Map)((Axis2MessageContext) synCtx).getAxis2MessageContext()
.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
JsonObject headers = EIPUtils.convertMapToJsonObj(transportHeaders);
result.put(ExpressionConstants.HEADERS, headers);
result.put(ExpressionConstants.ATTRIBUTES, CallMediatorEnrichUtil.populateTransportAttributes(synCtx));
synCtx.setVariable(key, result);
}
break;
default: {
synLog.error("Case mismatch for type: " + targetType);
}
Expand Down Expand Up @@ -683,6 +729,14 @@ public void setProperty(String property) {
this.property = property;
}

public void setVariable(Value variable) {
this.variable = variable;
}

public Value getVariable() {
return variable;
}

public void setTargetType(int targetType) {
this.targetType = targetType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.commons.logging.LogFactory;
import org.apache.http.protocol.HTTP;
import org.apache.synapse.MessageContext;
import org.apache.synapse.SynapseConstants;
import org.apache.synapse.SynapseException;
import org.apache.synapse.SynapseLog;
import org.apache.synapse.core.axis2.Axis2MessageContext;
Expand All @@ -58,6 +59,7 @@ public class CallMediatorEnrichUtil {
public static final String ENVELOPE = "envelope";
public static final String BODY = "body";
public static final String INLINE = "inline";
public static final String VARIABLE = "variable";

public static final String JSON_TYPE = "application/json";
public static final String TEXT_TYPE = "text/plain";
Expand All @@ -75,6 +77,8 @@ public static int convertTypeToInt(String type) {
return EnrichMediator.CUSTOM;
} else if (type.equals(INLINE)) {
return EnrichMediator.INLINE;
} else if (type.equals(VARIABLE)) {
return EnrichMediator.VARIABLE;
}
return -1;
}
Expand Down Expand Up @@ -297,5 +301,25 @@ public static SynapseLog getLog(MessageContext synCtx) {
return new MediatorLog(log, false, synCtx);
}

/**
* Populates the transport attributes of the message context to a JSON object.
*
* @param synCtx The message context.
* @return The JSON object containing the transport attributes.
*/
public static JsonObject populateTransportAttributes(MessageContext synCtx) {
JsonObject attributes = new JsonObject();
Object httpStatusCodeObj = ((Axis2MessageContext) synCtx).getAxis2MessageContext().getProperty(
SynapseConstants.HTTP_SC);
if (httpStatusCodeObj != null) {
if (httpStatusCodeObj instanceof String) {
attributes.addProperty("statusCode", (String) httpStatusCodeObj);
} else if (httpStatusCodeObj instanceof Integer) {
attributes.addProperty("statusCode", (Integer) httpStatusCodeObj);
}
}
return attributes;
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Represents a node in the AST that accesses a value in the payload or variable.
Expand Down Expand Up @@ -126,6 +128,33 @@ public ExpressionResult evaluate(EvaluationContext context, boolean isObjectValu
// if no expression just return variable
if (StringUtils.isEmpty(expressionToEvaluate)) {
result = variable;
} else if (variable instanceof Map) {
if (StringUtils.isNotEmpty(expressionToEvaluate)) {
expressionToEvaluate = expressionToEvaluate.startsWith(".") ? "var" + expressionToEvaluate
: "var." + expressionToEvaluate;
}
String[] keyAndExpression = ExpressionUtils.extractVariableAndJsonPath(expressionToEvaluate);
String key = keyAndExpression[0];
String expression = keyAndExpression[1];
if (StringUtils.isNotEmpty(expression)) {
expression = expression.startsWith(".") ? "$" + expression : "$." + expression;
}
Object keyValue = ((Map) variable).get(key);
if (keyValue == null) {
throw new EvaluationException("Could not find key: " + key + " in the variable: " + variable);
} else if (StringUtils.isEmpty(expression)) {
result = keyValue;
} else if (keyValue instanceof JsonElement) {
try {
result = JsonPath.parse(keyValue.toString()).read(expression);
} catch (PathNotFoundException e) {
// convert jsonPath error to native one
throw new EvaluationException(e.getMessage());
}
} else {
throw new EvaluationException("Could not evaluate JSONPath expression: " + expression
+ " on non-JSON object");
}
} else {
expressionToEvaluate = expressionToEvaluate.startsWith(".") ? "$" + expressionToEvaluate
: "$." + expressionToEvaluate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,6 @@ public class ExpressionConstants {

public static final String UNKNOWN = "unknown";
public static final String VAULT_LOOKUP = "wso2:vault-lookup('";
public static final String HEADERS = "headers";
public static final String ATTRIBUTES = "attributes";
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,11 @@ public void testVariableAccess() {
"var.random", 0, 1));
Assert.assertEquals("", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.num1[0]", 0, 1));
Assert.assertEquals("201", TestUtils.evaluateExpressionWithPayloadAndVariables(
"var.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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package org.apache.synapse.util.synapse.expression;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
Expand Down Expand Up @@ -97,12 +98,18 @@ public class TestUtils {
" \"selectedCategory\": \"biography\"\n" +
"}\n";

private static final JsonObject responseHeaders;

private static final JsonObject responseAttributes;

private static final String PAYLOAD3 = "[\"When\",\"my\",\"time\",\"comes\",\"Forget\",\"the\",\"wrong\",\"that\"" +
",\"I've\",\"done\"]";
private static final Map<String, Object> variableMap1;

private static final Map<String, Object> variableMap2;

private static final Map<String, Object> variableMap3;

static {
variableMap1 = new HashMap<>();
variableMap1.put("name", "John");
Expand All @@ -119,6 +126,18 @@ public class TestUtils {
variableMap2.put("json1", PAYLOAD1);
variableMap2.put("json2", PAYLOAD2);
variableMap2.put("json3", "[1,2,3,\"abc\"]");
variableMap3 = new HashMap<>();
responseHeaders = new JsonObject();
responseHeaders.addProperty("Content-Type", "application/json");
responseHeaders.addProperty("Content-Length", "101");
responseAttributes = new JsonObject();
responseAttributes.addProperty("statusCode", 201);
Map<String, Object> result = new HashMap<>();
result.put("headers", responseHeaders);
result.put("attributes", responseAttributes);
result.put("payload", JsonParser.parseString(PAYLOAD2));
variableMap3.put("fileRead_1", result);

try {
synCtx = org.apache.synapse.mediators.TestUtils.getAxis2MessageContext("<test/>", null);
} catch (Exception e) {
Expand Down Expand Up @@ -151,6 +170,10 @@ public static String evaluateExpressionWithPayloadAndVariables(String expression
for (Map.Entry<String, Object> entry : variableMap2.entrySet()) {
synCtx.setVariable(entry.getKey(), entry.getValue());
}
} else if (variableMapId == 3) {
for (Map.Entry<String, Object> entry : variableMap3.entrySet()) {
synCtx.setVariable(entry.getKey(), entry.getValue());
}
}
SynapseExpression synapsePath = new SynapseExpression(expression);
return synapsePath.stringValueOf(synCtx);
Expand Down
Loading