Skip to content

Commit

Permalink
Cache inline synapse expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
SanojPunchihewa committed Jan 20, 2025
1 parent 19ef60e commit e5990aa
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.synapse.Mediator;
import org.apache.synapse.SynapseException;
import org.apache.synapse.mediators.builtin.LogMediator;
import org.jaxen.JaxenException;

import javax.xml.namespace.QName;
import java.util.Properties;
Expand Down Expand Up @@ -71,8 +73,15 @@ public Mediator createSpecificMediator(OMElement elem, Properties properties) {
boolean containMessageTemplate = false;
OMElement messageElement = elem.getFirstChildWithName(ELEMENT_MESSAGE_Q);
if (messageElement != null && messageElement.getText() != null) {
logMediator.setMessageTemplate(messageElement.getText());
containMessageTemplate = true;
try {
containMessageTemplate = true;
logMediator.setMessageTemplate(messageElement.getText());
logMediator.processTemplateAndSetContentAware();
} catch (JaxenException e) {
String msg = "Invalid message template : " + e.getMessage();
log.error(msg);
throw new SynapseException(msg);
}
}

// Set the high level set of properties to be logged (i.e. log level)
Expand Down Expand Up @@ -126,7 +135,6 @@ public Mediator createSpecificMediator(OMElement elem, Properties properties) {
}

logMediator.addAllProperties(MediatorPropertyFactory.getMediatorProperties(elem));
logMediator.processTemplateAndSetContentAware();
addAllCommentChildrenToList(elem, logMediator.getCommentsList());

return logMediator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@
import org.apache.synapse.mediators.AbstractMediator;
import org.apache.synapse.mediators.MediatorProperty;
import org.apache.synapse.util.InlineExpressionUtil;
import org.apache.synapse.util.xpath.SynapseExpression;
import org.jaxen.JaxenException;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* Logs the specified message into the configured logger. The log levels specify
Expand Down Expand Up @@ -80,6 +83,7 @@ public class LogMediator extends AbstractMediator {

private String messageTemplate = "";
private boolean isContentAware = false;
private final Map<String, SynapseExpression> inlineExpressionCache = new ConcurrentHashMap<>();

/**
* Logs the current message according to the supplied semantics
Expand Down Expand Up @@ -285,6 +289,12 @@ public void addProperty(MediatorProperty p) {

public void addAllProperties(List<MediatorProperty> list) {
properties.addAll(list);
for (MediatorProperty property : properties) {
if (property.getExpression() != null && property.getExpression().isContentAware()) {
isContentAware = true;
return;
}
}
}

public List<MediatorProperty> getProperties() {
Expand Down Expand Up @@ -324,7 +334,8 @@ private String trimLeadingSeparator(StringBuffer sb) {

private void processMessageTemplate(StringBuffer stringBuffer, MessageContext synCtx, String template) {
try {
stringBuffer.append(InlineExpressionUtil.processInLineSynapseExpressionTemplate(synCtx, template));
stringBuffer.append(InlineExpressionUtil.processInLineSynapseExpressionTemplate(synCtx, template,
inlineExpressionCache));
} catch (JaxenException e) {
handleException("Failed to process the message template : " + template, e, synCtx);
}
Expand All @@ -333,21 +344,14 @@ private void processMessageTemplate(StringBuffer stringBuffer, MessageContext sy
@Override
public boolean isContentAware() {

return isContentAware;
if (logLevel == MESSAGE_TEMPLATE || logLevel == CUSTOM) {
return isContentAware;
}
return true;
}

public void processTemplateAndSetContentAware() {
public void processTemplateAndSetContentAware() throws JaxenException {

if (logLevel == MESSAGE_TEMPLATE || logLevel == CUSTOM) {
for (MediatorProperty property : properties) {
if (property.getExpression() != null && property.getExpression().isContentAware()) {
isContentAware = true;
return;
}
}
isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(messageTemplate);
} else {
isContentAware = true;
}
isContentAware = InlineExpressionUtil.initInlineSynapseExpressions(messageTemplate, inlineExpressionCache);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
import org.apache.synapse.SynapseException;
import org.apache.synapse.commons.json.JsonUtil;
import org.apache.synapse.mediators.transform.ArgumentDetails;
import org.apache.synapse.util.InlineExpressionUtil;
import org.apache.synapse.util.xpath.SynapseExpression;
import org.jaxen.JaxenException;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.stream.XMLStreamException;
Expand All @@ -53,6 +55,7 @@ public class RegexTemplateProcessor extends TemplateProcessor {
private final Pattern pattern = Pattern.compile("\"\\$\\{(.+?)\\}\"|\\$\\{(.+?)\\}|\\$(\\d+)");

private final Gson gson = new Gson();
private final Map<String, SynapseExpression> inlineExpressionCache = new ConcurrentHashMap<>();

@Override
public String processTemplate(String template, String mediaType, MessageContext synCtx) {
Expand All @@ -63,7 +66,16 @@ public String processTemplate(String template, String mediaType, MessageContext
}

@Override
public void init() {
public void init() throws SynapseException {
String format = getFormat();
if (format != null) {
try {
InlineExpressionUtil.initInlineSynapseExpressions(format, inlineExpressionCache);
} catch (JaxenException e) {
String msg = "Invalid Payload format : " + e.getMessage();
throw new SynapseException(msg);
}
}
this.readInputFactoryProperties();
}

Expand Down Expand Up @@ -178,10 +190,15 @@ private String prepareJSONPrimitiveReplacementValue(Object expressionResult, Str
*/
private Object evaluateExpression(String expression, MessageContext synCtx) throws JaxenException {

SynapseExpression expressionObj = inlineExpressionCache.get(expression);
if (expressionObj == null) {
expressionObj = new SynapseExpression(expression);
inlineExpressionCache.put(expression, expressionObj);
}
if (expression.contains("xpath(")) {
return new SynapseExpression(expression).stringValueOf(synCtx);
return expressionObj.stringValueOf(synCtx);
}
return new SynapseExpression(expression).objectValueOf(synCtx);
return expressionObj.objectValueOf(synCtx);
}

private String escapeJson(String value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.MessageContext;
import org.apache.synapse.SynapseException;
import org.apache.synapse.commons.json.JsonUtil;
import org.apache.synapse.config.xml.SynapsePath;
import org.apache.synapse.mediators.transform.Argument;
Expand Down Expand Up @@ -90,7 +91,7 @@ public abstract class TemplateProcessor {
/**
* Execute pre-processing steps if needed
*/
public abstract void init();
public abstract void init() throws SynapseException;

/**
* Goes through SynapsePath argument list, evaluating each by calling stringValueOf and returns a HashMap String, String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.synapse.util.xpath.SynapseXPath;
import org.jaxen.JaxenException;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.stream.XMLStreamException;
Expand Down Expand Up @@ -203,42 +204,53 @@ private static boolean isValidXML(String stringToValidate) {
}

/**
* Checks whether inline template contains content aware synapse expressions.
* Initialize the inline synapse expressions in the inline text and return whether the inline text is content aware
* Inline expressions will be denoted inside ${}
* e.g.: ${var.var1}, ${payload.element.id}
*
* @param inlineText Inline text string
* @param inlineText Inline text string
* @param expressionCache Cache to store the synapse expressions
* @return true if the string contains content aware inline synapse expressions, false otherwise
*/
public static boolean isInlineSynapseExpressionsContentAware(String inlineText) {
public static boolean initInlineSynapseExpressions(String inlineText, Map<String, SynapseExpression> expressionCache)
throws JaxenException {

boolean isContentAware = false;
Matcher matcher = SYNAPSE_EXPRESSION_PLACEHOLDER_PATTERN.matcher(inlineText);
while (matcher.find()) {
// Extract the expression inside ${...}
String expression = matcher.group(1);
if (SynapseExpressionUtils.isSynapseExpressionContentAware(expression)) {
return true;
// Extract the expression inside ${...} and add it to the cache
String placeholder = matcher.group(1);
SynapseExpression expression = new SynapseExpression(placeholder);
if (expression.isContentAware()) {
isContentAware = true;
}
expressionCache.put(placeholder, expression);
}
return false;
return isContentAware;
}

/**
* Process the inline template and replace the synapse expressions with the resolved values
*
* @param synCtx Message Context
* @param template Inline template
* @param synCtx Message Context
* @param template Inline template
* @param expressionCache Cache to store the synapse expressions
* @return Processed inline template
*/
public static String processInLineSynapseExpressionTemplate(MessageContext synCtx, String template)
public static String processInLineSynapseExpressionTemplate(MessageContext synCtx, String template,
Map<String, SynapseExpression> expressionCache)
throws JaxenException {

Matcher matcher = SYNAPSE_EXPRESSION_PLACEHOLDER_PATTERN.matcher(template);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
// Extract the expression inside ${...}
String placeholder = matcher.group(1);
SynapseExpression expression = new SynapseExpression(placeholder);
SynapseExpression expression = expressionCache.get(placeholder);
if (expression == null) {
expression = new SynapseExpression(placeholder);
expressionCache.put(placeholder, expression);
}
String replacement = expression.stringValueOf(synCtx);
matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.apache.synapse.mediators.TestUtils;
import org.junit.Assert;

import java.util.HashMap;

public class InlineExpressionUtilTest extends TestCase {

private static String payload = "{\n" +
Expand Down Expand Up @@ -83,10 +85,10 @@ public void testsInLineSynapseExpressionTemplate1() throws Exception {
MessageContext mc = TestUtils.getTestContextJson(payload, null);
String inlineExpression = "Processing payload : ${payload.team[0]}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
boolean isContentAware = InlineExpressionUtil.initInlineSynapseExpressions(inlineExpression, new HashMap<>());
Assert.assertTrue("Inline expression content aware should be true", isContentAware);

String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression);
String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression, new HashMap<>());
Assert.assertEquals("Inline expression result mismatch", expected, result);
}

Expand All @@ -100,10 +102,10 @@ public void testsInLineSynapseExpressionTemplate2() throws Exception {
MessageContext mc = TestUtils.getTestContextJson(payload, null);
String inlineExpression = "Processing user : ${payload.team[0].name}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
boolean isContentAware = InlineExpressionUtil.initInlineSynapseExpressions(inlineExpression, new HashMap<>());
Assert.assertTrue("Inline expression content aware should be true", isContentAware);

String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression);
String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression, new HashMap<>());
Assert.assertEquals("Inline expression result mismatch", expected, result);
}

Expand All @@ -117,10 +119,10 @@ public void testsInLineSynapseExpressionTemplate3() throws Exception {
MessageContext mc = TestUtils.getTestContextJson(payload, null);
String inlineExpression = "Processing user : ${payload.team[0].age}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
boolean isContentAware = InlineExpressionUtil.initInlineSynapseExpressions(inlineExpression, new HashMap<>());
Assert.assertTrue("Inline expression content aware should be true", isContentAware);

String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression);
String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression, new HashMap<>());
Assert.assertEquals("Inline expression result mismatch", expected, result);
}

Expand All @@ -140,10 +142,10 @@ public void testsInLineSynapseExpressionTemplate4() throws Exception {
mc.setVariable("address", jsonObject);
String inlineExpression = "Processing user with age : ${vars.age} lives at ${vars.address}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
boolean isContentAware = InlineExpressionUtil.initInlineSynapseExpressions(inlineExpression, new HashMap<>());
Assert.assertFalse("Inline expression content aware should be false", isContentAware);

String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression);
String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression, new HashMap<>());
Assert.assertEquals("Inline expression result mismatch", expected, result);
}

Expand All @@ -163,10 +165,10 @@ public void testsInLineSynapseExpressionTemplate5() throws Exception {
String inlineExpression = "Processing user : ${payload.team[0].name}, role : ${vars.role}, " +
"experience : ${vars.experience.level} ${properties.synapse.duration}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
boolean isContentAware = InlineExpressionUtil.initInlineSynapseExpressions(inlineExpression, new HashMap<>());
Assert.assertTrue("Inline expression content aware should be true", isContentAware);

String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression);
String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression, new HashMap<>());
Assert.assertEquals("Inline expression result mismatch", expected, result);
}

Expand All @@ -182,10 +184,10 @@ public void testsInLineSynapseExpressionTemplate6() throws Exception {
mc.setProperty("method", "get");
String inlineExpression = "Processing using endpoint : ${vars.endpoint}, method : ${properties.synapse.method}, role : ${payload.team[2].role}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
boolean isContentAware = InlineExpressionUtil.initInlineSynapseExpressions(inlineExpression, new HashMap<>());
Assert.assertTrue("Inline expression content aware should be true", isContentAware);

String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression);
String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression, new HashMap<>());
Assert.assertEquals("Inline expression result mismatch", expected, result);
}

Expand All @@ -207,10 +209,10 @@ public void testsInLineSynapseExpressionTemplate7() throws Exception {
mc.setVariable("endpoint", "https://test.wso2.com/");
String inlineExpression = "Using endpoint : ${vars.endpoint} to process book : ${xpath('//catalog/book[1]')}";

boolean isContentAware = InlineExpressionUtil.isInlineSynapseExpressionsContentAware(inlineExpression);
boolean isContentAware = InlineExpressionUtil.initInlineSynapseExpressions(inlineExpression, new HashMap<>());
Assert.assertTrue("Inline expression content aware should be true", isContentAware);

String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression);
String result = InlineExpressionUtil.processInLineSynapseExpressionTemplate(mc, inlineExpression, new HashMap<>());
Assert.assertEquals("Inline expression result mismatch", expected, result);
}
}

0 comments on commit e5990aa

Please sign in to comment.