diff --git a/modules/core/src/main/java/org/apache/synapse/mediators/transform/pfutils/RegexTemplateProcessor.java b/modules/core/src/main/java/org/apache/synapse/mediators/transform/pfutils/RegexTemplateProcessor.java index 1a6ba8958c..ee3b1aa542 100644 --- a/modules/core/src/main/java/org/apache/synapse/mediators/transform/pfutils/RegexTemplateProcessor.java +++ b/modules/core/src/main/java/org/apache/synapse/mediators/transform/pfutils/RegexTemplateProcessor.java @@ -19,15 +19,29 @@ package org.apache.synapse.mediators.transform.pfutils; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import org.apache.axiom.om.OMElement; +import org.apache.axiom.om.OMException; +import org.apache.axis2.AxisFault; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.commons.text.StringEscapeUtils; import org.apache.synapse.MessageContext; +import org.apache.synapse.SynapseException; +import org.apache.synapse.commons.json.JsonUtil; import org.apache.synapse.mediators.transform.ArgumentDetails; +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.regex.Matcher; import java.util.regex.Pattern; +import javax.xml.stream.XMLStreamException; /** * TemplateProcessor implementation for Regex based templates @@ -35,7 +49,10 @@ public class RegexTemplateProcessor extends TemplateProcessor { private static final Log log = LogFactory.getLog(RegexTemplateProcessor.class); - private final Pattern pattern = Pattern.compile("\\$(\\d)+"); + // Pattern matches "${...}" (quoted), ${...} (unquoted), and $n + private final Pattern pattern = Pattern.compile("\"\\$\\{(.+?)\\}\"|\\$\\{(.+?)\\}|\\$(\\d+)"); + + private final Gson gson = new Gson(); @Override public String processTemplate(String template, String mediaType, MessageContext synCtx) { @@ -72,25 +89,125 @@ private void replace(String format, StringBuffer result, String mediaType, Messa } try { while (matcher.find()) { - String matchSeq = matcher.group(); - replacement = getReplacementValue(argValues, matchSeq); - replacementEntry = replacement.entrySet().iterator().next(); - replacementValue = prepareReplacementValue(mediaType, synCtx, replacementEntry); - matcher.appendReplacement(result, replacementValue); + if (matcher.group(1) != null) { + // Handle "${...}" pattern (with quotes) + String expression = matcher.group(1); + Object expressionResult = new SynapseExpression(expression).objectValueOf(synCtx); + if (expressionResult instanceof JsonPrimitive) { + replacementValue = ((JsonPrimitive) expressionResult).getAsString(); + if (XML_TYPE.equals(mediaType)) { + replacementValue = StringEscapeUtils.escapeXml10(replacementValue); + } else if (JSON_TYPE.equals(mediaType)) { + replacementValue = escapeSpecialChars(replacementValue); + } + } else if (expressionResult instanceof JsonElement) { + replacementValue = escapeJson(Matcher.quoteReplacement(gson.toJson(expressionResult))); + if (XML_TYPE.equals(mediaType)) { + replacementValue = convertJsonToXML(replacementValue); + } + } else { + replacementValue = expressionResult.toString(); + } + if (JSON_TYPE.equals(mediaType) && isXML(replacementValue)) { + // consider the replacement value as a literal XML + replacementValue = Matcher.quoteReplacement(replacementValue); + replacementValue = escapeSpecialChars(replacementValue); + } + matcher.appendReplacement(result, "\"" + replacementValue + "\""); + } else if (matcher.group(2) != null) { + // Handle ${...} pattern (without quotes) + String expression = matcher.group(2); + Object expressionResult = new SynapseExpression(expression).objectValueOf(synCtx); + replacementValue = expressionResult.toString(); + if (expressionResult instanceof JsonPrimitive) { + replacementValue = ((JsonPrimitive) expressionResult).getAsString(); + if (XML_TYPE.equals(mediaType)) { + replacementValue = StringEscapeUtils.escapeXml10(replacementValue); + } + } else if (expressionResult instanceof JsonElement) { + if (XML_TYPE.equals(mediaType)) { + replacementValue = convertJsonToXML(expressionResult.toString()); + } else { + replacementValue = Matcher.quoteReplacement(gson.toJson(expressionResult)); + } + } + if (JSON_TYPE.equals(mediaType) && isXML(replacementValue)) { + replacementValue = convertXMLToJSON(replacementValue); + } + matcher.appendReplacement(result, replacementValue); + } else if (matcher.group(3) != null) { + // Handle $n pattern + String matchSeq = matcher.group(3); + replacement = getReplacementValue(argValues, matchSeq); + replacementEntry = replacement.entrySet().iterator().next(); + replacementValue = prepareReplacementValue(mediaType, synCtx, replacementEntry); + matcher.appendReplacement(result, replacementValue); + } } } catch (ArrayIndexOutOfBoundsException e) { log.error("#replace. Mis-match detected between number of formatters and arguments", e); + } catch (JaxenException e) { + throw new SynapseException("Error evaluating expression" , e); } matcher.appendTail(result); } + private String escapeJson(String value) { + // Manual escape for JSON: escaping double quotes and backslashes + return value.replace("\"", "\\\"").replace("\\", "\\\\"); + } + + private String convertJsonToXML(String replacementValue) { + + try { + replacementValue = escapeSpecialCharactersOfXml(replacementValue); + OMElement omXML = JsonUtil.toXml(IOUtils.toInputStream(replacementValue), false); + if (JsonUtil.isAJsonPayloadElement(omXML)) { // remove from result. + Iterator children = omXML.getChildElements(); + String childrenStr = ""; + while (children.hasNext()) { + childrenStr += (children.next()).toString().trim(); + } + replacementValue = childrenStr; + } else { + replacementValue = omXML.toString(); + } + } catch (AxisFault e) { + handleException( + "Error converting JSON to XML, please check your expressions return valid JSON: "); + } + return replacementValue; + } + + private String convertXMLToJSON(String replacementValue) { + + try { + replacementValue = "" + replacementValue + ""; + OMElement omXML = convertStringToOM(replacementValue); + replacementValue = JsonUtil.toJsonString(omXML).toString(); + replacementValue = escapeSpecialCharactersOfJson(replacementValue); + } catch (XMLStreamException e) { + handleException( + "Error parsing XML for JSON conversion, please check your expressions return valid XML: "); + } catch (AxisFault e) { + handleException("Error converting XML to JSON"); + } catch (OMException e) { + // if the logic comes to this means, it was tried as a XML, which means it has + // "<" as starting element and ">" as end element, so basically if the logic comes here, that means + // value is a string value, that means No conversion required, as path evaluates to regular String. + replacementValue = escapeSpecialChars(replacementValue); + + } + return replacementValue; + } + private HashMap getReplacementValue(HashMap[] argValues, String matchSeq) { HashMap replacement; int argIndex; try { - argIndex = Integer.parseInt(matchSeq.substring(1)); + argIndex = Integer.parseInt(matchSeq); } catch (NumberFormatException e) { argIndex = Integer.parseInt(matchSeq.substring(2, matchSeq.length() - 1)); }