Source.java
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.synapse.mediators.elementary;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.jayway.jsonpath.JsonPath;
import org.apache.axiom.om.*;
import org.apache.axiom.om.impl.llom.OMTextImpl;
import org.apache.axiom.om.util.ElementHelper;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPHeaderBlock;
import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.MessageContext;
import org.apache.synapse.SynapseLog;
import org.apache.synapse.commons.json.JsonUtil;
import org.apache.synapse.config.xml.SynapsePath;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.apache.synapse.util.InlineExpressionUtil;
import org.apache.synapse.util.MessageHelper;
import org.apache.synapse.util.xpath.SynapseJsonPath;
import org.jaxen.JaxenException;
import java.util.ArrayList;
import java.util.List;
/**
* The source of the XML node to be stored. The source can be a
* 1. Property
* 2. XPath Expression
* 3. SOAP Envelope
* 4. SOAP Body
* <p/>
* If clone is true a clone will be create and stored from the origincal content. Otherwise a
* reference will be stored.
* <p/>
* In case of property a OMElement is stored in a property and it will be fetched.
* <p/>
* In case of a XPath expression, it will be evaluated to get the OMElement
* <p/>
* In case of SOAPEnvelope entire SOAP envelope will be stored
* <p/>
* In case of Body, the first child of body will be stored
*/
public class Source {
private SynapsePath xpath = null;
private String property = null;
private int sourceType = EnrichMediator.CUSTOM;
private boolean clone = true;
private OMNode inlineOMNode = null;
private OMNode initialInlineOMNode = null;
private String inlineKey = null;
private static final Log log = LogFactory.getLog(Source.class);
public ArrayList<OMNode> evaluate(MessageContext synCtx, SynapseLog synLog)
throws JaxenException {
ArrayList<OMNode> sourceNodeList = new ArrayList<OMNode>();
if (sourceType == EnrichMediator.CUSTOM) {
assert xpath != null : "XPath should be non null in case of CUSTOM";
List selectedNodeList = xpath.selectNodes(synCtx);
if (selectedNodeList != null && selectedNodeList.size() != 0) {
for (Object o : selectedNodeList) {
if (o instanceof OMElement) {
if (clone) {
OMElement ins = ((OMElement) o).cloneOMElement();
if (o instanceof SOAPHeaderBlock) {
SOAPFactory fac = (SOAPFactory) ((OMElement) o).getOMFactory();
try {
sourceNodeList.add(ElementHelper.toSOAPHeaderBlock(ins, fac));
} catch (Exception e) {
synLog.error(e);
throw new JaxenException(e);
}
} else {
sourceNodeList.add(ins);
}
} else {
sourceNodeList.add((OMElement) o);
}
} else if (o instanceof OMText) {
sourceNodeList.add((OMText) o);
} else if (o instanceof String) {
OMFactory fac = OMAbstractFactory.getOMFactory();
sourceNodeList.add(fac.createOMText(o.toString()));
}
}
} else {
synLog.error("Specified node by xpath cannot be found.");
}
} else if (sourceType == EnrichMediator.BODY) {
if (clone) {
if (synCtx.getEnvelope().getBody().getFirstElement() != null) {
sourceNodeList.add(synCtx.getEnvelope().getBody().getFirstElement()
.cloneOMElement());
}
} else {
if (synCtx.getEnvelope().getBody().getFirstElement() != null) {
sourceNodeList.add(synCtx.getEnvelope().getBody().getFirstElement());
}
}
} else if (sourceType == EnrichMediator.ENVELOPE) {
if (clone) {
sourceNodeList.add(MessageHelper.cloneSOAPEnvelope(synCtx.getEnvelope()));
} else {
sourceNodeList.add(synCtx.getEnvelope());
}
} else if (sourceType == EnrichMediator.PROPERTY) {
assert property != null : "property shouldn't be null when type is PROPERTY";
Object o = synCtx.getProperty(property);
if (o instanceof OMElement) {
if (clone) {
sourceNodeList.add(((OMElement) o).cloneOMElement());
}
else{
sourceNodeList.add((OMElement) o);
}
} else if (o instanceof String) {
String sourceStr = (String) o;
OMFactory fac = OMAbstractFactory.getOMFactory();
sourceNodeList.add(fac.createOMText(sourceStr));
} else if (o instanceof ArrayList) {
ArrayList nodesList;
if (clone) {
nodesList = MessageHelper.cloneArrayList((ArrayList) o);
} else {
nodesList = (ArrayList) o;
}
for (Object node : nodesList) {
if (node instanceof OMElement) {
if (node instanceof SOAPEnvelope) {
SOAPEnvelope soapEnvelope = (SOAPEnvelope) node;
String soapNamespace = null;
if (soapEnvelope.getNamespace() != null) {
soapNamespace = soapEnvelope.getNamespace().getNamespaceURI();
}
if (soapEnvelope.getHeader() == null && soapNamespace != null) {
SOAPFactory soapFactory;
if (soapNamespace.equals(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI)) {
soapFactory = OMAbstractFactory.getSOAP12Factory();
} else {
soapFactory = OMAbstractFactory.getSOAP11Factory();
}
soapFactory.createSOAPHeader(soapEnvelope);
}
sourceNodeList.add(soapEnvelope);
} else {
OMElement ele = (OMElement) node;
sourceNodeList.add(ele);
}
} else if (node instanceof OMText) {
sourceNodeList.add((OMText)node);
}
}
} else if (o instanceof JsonElement) {
// Handling property with JSON type
String sourceStr = o.toString();
OMFactory fac = OMAbstractFactory.getOMFactory();
sourceNodeList.add(fac.createOMText(sourceStr));
} else {
synLog.error("Invalid source property type.");
}
} else if (sourceType == EnrichMediator.INLINE) {
if (inlineOMNode instanceof OMElement) {
OMElement inlineOMElement = (OMElement) inlineOMNode;
if (inlineOMElement.getQName().getLocalPart().equals("Envelope")) {
SOAPEnvelope soapEnvelope = getSOAPEnvFromOM(inlineOMElement);
if (soapEnvelope != null) {
sourceNodeList.add(soapEnvelope);
} else {
synLog.error("Inline Source is not a valid SOAPEnvelope.");
}
} else {
sourceNodeList.add(inlineOMElement.cloneOMElement());
}
} else if (inlineOMNode instanceof OMText) {
sourceNodeList.add(inlineOMNode);
} else if (inlineKey != null) {
Object inlineObj = synCtx.getEntry(inlineKey);
if (inlineObj instanceof OMElement) {
if (((OMElement) inlineObj).getQName().getLocalPart().equals("Envelope")) {
SOAPEnvelope soapEnvelope = getSOAPEnvFromOM((OMElement) inlineObj);
if (soapEnvelope != null) {
sourceNodeList.add(soapEnvelope);
} else {
synLog.error("Specified Resource as Source is not a valid SOAPEnvelope.");
}
} else {
sourceNodeList.add((OMElement) inlineObj);
}
} else if (inlineObj instanceof OMText) {
sourceNodeList.add((OMText)inlineObj);
} else if (inlineObj instanceof String) {
sourceNodeList.add(
OMAbstractFactory.getOMFactory().createOMText(inlineObj.toString()));
} else {
synLog.error("Specified Resource as Source is not valid.");
}
} else {
synLog.error("Inline Source Content is not valid.");
}
// If the initialInlineOMNode is not null, it means that inline OM Node has been overridden with the
// inline string containing resolved dynamic values. Therefore, we should set the initial OM Node back
// which contains the original inline value
if (initialInlineOMNode != null) {
this.inlineOMNode = initialInlineOMNode;
}
}
return sourceNodeList;
}
private SOAPEnvelope getSOAPEnvFromOM(OMElement inlineElement) {
SOAPFactory soapFactory;
if (inlineElement.getQName().getNamespaceURI().equals(
SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI)) {
soapFactory = OMAbstractFactory.getSOAP12Factory();
} else {
soapFactory = OMAbstractFactory.getSOAP11Factory();
}
StAXSOAPModelBuilder builder = new StAXSOAPModelBuilder(inlineElement.getXMLStreamReader(),
soapFactory, inlineElement.getQName().getNamespaceURI());
return builder.getSOAPEnvelope();
}
/**
* This method will evaluate a specified source json element.
*
* @param synCtx - Current Message Context
* @param synLog - Default Logger for the package
* @param sourcePropertyJson Parsed Json element
* @return A HashMap with the following keys: <br/>
* [1] "errorsExistInSrcTag" - holds either true or false <br/>
* [2] "evaluatedSrcJsonElement" - holds the evaluated Json Element as an Object
*/
public JsonElement evaluateJson(MessageContext synCtx, SynapseLog synLog,
JsonElement sourcePropertyJson) throws JaxenException {
JsonElement object = null;
String jsonPath = null;
JsonParser parser = new JsonParser();
if (xpath != null) {
SynapseJsonPath sourceJsonPath = (SynapseJsonPath) this.xpath;
if (InlineExpressionUtil.checkForInlineExpressions(sourceJsonPath.toString())) {
try {
String jsonpath = sourceJsonPath.toString();
if (jsonpath.startsWith("json-eval(")) {
jsonpath = jsonpath.substring(10, jsonpath.length() - 1);
}
sourceJsonPath =
new SynapseJsonPath(InlineExpressionUtil.replaceDynamicValues(synCtx, jsonpath));
} catch (JaxenException e) {
log.error("Error occurred while evaluating JSONPath", e);
}
}
jsonPath = sourceJsonPath.getJsonPathExpression();
}
org.apache.axis2.context.MessageContext context = ((Axis2MessageContext) synCtx).getAxis2MessageContext();
if (!JsonUtil.hasAJsonPayload(context)) {
synLog.error("JSON payload not found in message context");
}
switch (sourceType) {
case EnrichMediator.CUSTOM: {
assert jsonPath != null : "JSONPath should be non null in case of CUSTOM";
String jsonString = JsonUtil.jsonPayloadToString(context);
object = JsonPath.parse(jsonString).read(jsonPath);
if (!clone) {
// when cloning is false, remove the element in JSON path from payload
String modifiedJsonString = JsonPath.parse(jsonString).delete(jsonPath).jsonString();
try {
JsonUtil.getNewJsonPayload(context, modifiedJsonString, true, true);
} catch (Exception ex) {
synLog.error("Error while setting json payload, when cloning is false");
}
}
break;
}
case EnrichMediator.BODY: {
String jsonPayload = JsonUtil.jsonPayloadToString(context);
object = parser.parse(jsonPayload);
break;
}
case EnrichMediator.INLINE: {
assert inlineOMNode != null
|| inlineKey != null : "inlineJSONNode or key shouldn't be null when type is INLINE";
if (inlineOMNode instanceof OMText) {
object = JsonPath.parse(((OMTextImpl) inlineOMNode).getText()).json();
} else if (inlineKey != null && !inlineKey.trim().equals("")) {
Object inlineObj = synCtx.getEntry(inlineKey);
if ((inlineObj instanceof String) && !(((String) inlineObj).trim().equals(""))) {
object = JsonPath.parse(((String) inlineObj)).json();
} else {
synLog.error("Source failed to get inline JSON" + "inlineKey=" + inlineKey);
}
} else {
synLog.error("Source failed to get inline JSON" + "inlineJSONNode=" + inlineOMNode + ", inlineKey="
+ inlineKey);
}
// If the initialInlineOMNode is not null, it means that inline OM Node has been overridden with the
// inline string containing resolved dynamic values. Therefore, we should set the initial OM Node back
// which contains the original inline value
if (initialInlineOMNode != null) {
this.inlineOMNode = initialInlineOMNode;
}
break;
}
case EnrichMediator.PROPERTY: {
assert property != null : "property shouldn't be null when type is PROPERTY";
if (sourcePropertyJson != null) {
object = sourcePropertyJson;
} else {
synLog.error("Source json object cannot be null");
}
break;
}
default: {
synLog.error("Case mismatch for type: " + sourceType);
}
}
return object;
}
public SynapsePath getXpath() {
return xpath;
}
public void setXpath(SynapsePath xpath) {
this.xpath = xpath;
}
public int getSourceType() {
return sourceType;
}
public void setSourceType(int sourceType) {
this.sourceType = sourceType;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
public boolean isClone() {
return clone;
}
public void setClone(boolean clone) {
this.clone = clone;
}
public void setInlineOMNode(OMNode inlineOMNode) {
this.inlineOMNode = inlineOMNode;
}
public OMNode getInlineOMNode() {
return inlineOMNode;
}
public String getInlineKey() {
return inlineKey;
}
public void setInlineKey(String inlineKey) {
this.inlineKey = inlineKey;
}
public OMNode getInitialInlineOMNode() {
return initialInlineOMNode;
}
public void setInitialInlineOMNode(OMNode inlineOMNodeWithExpressions) {
this.initialInlineOMNode = inlineOMNodeWithExpressions;
}
}