WSO2 ESB - Invoking Webservices with XML data within a tag of the payload - wso2

I have a requirement to invoke an external webservice(s) via the Middleware, with one of the tags in my payload containing embedded XML. Sample payload and sequence snippet below. I encounter the following issues.
Scenario 1 : (line 24) expression="get-property('PayloadXML')" - Upon issuing a send command, the webservice method is not recognized.
Scenario 2 : (line 24) expression="get-property('lPayload')" - Upon issuing a send command, the webservice method is successfully invoked. However, for the target system to successfully process the message, it would need to handle the CDATA element(wrapping).
When trying to invoke Scenario 2 via soapUI, the process is successful. From what I've researched (Passing CDATA in WSO2), soapUI seems to internally handle the CDATA element, before forwarding the message.
Now, I understand the way I'm setting scenario 2 is not ideal(more of a hack), but I'm unaware of any other ways to achieve this. I've read numerous blogs/posts and tried transforming(developing) the Payload via the XSLT mediator with no luck. I've also come across the following post http://www.yenlo.com/en/how-to-preserve-a-cdata-in-xml-that-is-circulating-in-a-wso2-enterprise-service-bus/ , but I can't seem to find the patch that is being referred to.
So my questions are as follows:
1. Are there any other ways/mechanisms for me to achieve my requirements?
2. Will the WSO2 ESB 4.9.0 release resolve the issues mentioned above?
Sample Payload :
<sample><test>MyData</test></sample>
Sequence Snippet :
<property xmlns:ns1="http://ws.wso2.org/dataservice"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
name="PayloadXML"
expression="$body/data-services-event/content/ns1:return/ns1:return/ns1:PayLoadXML"/>
<property xmlns:ns="http://org.apache.synapse/xsd"
name="lPayload"
expression="fn:concat(fn:concat('<![CDATA[',get-property('PayloadXML')), ']]>')"/>
<payloadFactory media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:log="http://mynamespace">
<soapenv:Header/>
<soapenv:Body>
<log:publishMessage>
<Payload xmlns="">$1</Payload>
</log:publishMessage>
</soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg xmlns:ns2="http://org.apache.synapse/xsd"
xmlns:ns="http://org.apache.synapse/xsd"
evaluator="xml"
expression="get-property('lPayload')"/>
</args>
</payloadFactory>

Here is a sample proxy service that receive XML data and send back a new XML message with a sub part of the input content in a CDATA section.
Send it :
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<PayloadXML>
<sample><test>MyData</test></sample>
</PayloadXML>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
You receive :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<log:publishMessage xmlns:log="http://mynamespace">
<Payload><![CDATA[<sample><test>MyData</test></sample>]]></Payload>
</log:publishMessage>
</soapenv:Body>
</soapenv:Envelope>
The proxy def :
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse" name="TestSOF" transports="http" statistics="disable" trace="disable" startOnLoad="true">
<target>
<inSequence>
<!-- extract xml content from the input message -->
<property name="xmlContent" expression="$body/PayloadXML/*[1]" type="OM"/>
<!-- compose a new message -->
<enrich>
<source type="inline" clone="true">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<log:publishMessage xmlns:log="http://mynamespace">
<Payload xmlns=""/>
</log:publishMessage>
</soapenv:Body>
</soapenv:Envelope>
</source>
<target type="envelope"/>
</enrich>
<!-- create a CDATA section for 'Payload' node -->
<script language="js">
importPackage(Packages.org.apache.axiom.om);
var payloadElmt = mc.getEnvelope().getBody().getFirstElement().getFirstElement();
var omText = payloadElmt.getOMFactory().createOMText(payloadElmt, mc.getProperty("xmlContent"), OMNode.CDATA_SECTION_NODE);
payloadElmt.addChild(omText)
</script>
<!-- send back this new message as a response for the caller -->
<header name="To" action="remove"/>
<property name="RESPONSE" value="true"/>
<property name="NO_ENTITY_BODY" scope="axis2" action="remove"/>
<send/>
</inSequence>
</target>
<description/>
</proxy>

If your basic requirement is to pass xml data within a tag, Here is an example for that.
Here I am using wso2 ESB 4.9.0. Basic thing is, you need to store the payload factory format in registry and use it in the payload factory configuration as bellow.
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="foo"
transports="https,http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<property xmlns:ns="http://org.apache.synapse/xsd"
name="Request"
expression="$body/child::*[fn:position()=1]"
scope="default"
type="STRING"/>
<payloadFactory media-type="xml">
<format key="conf:/repository/esb/myPF"/>
<args>
<arg evaluator="xml" expression="$ctx:Request"/>
<arg value="1"/>
</args>
</payloadFactory>
<send>
<endpoint>
<address uri="http://127.0.0.1:9763/services/Hello"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
<description/>
Above is my proxy service. I am getting the first child from the request ESB gets from the client and use it as the input for the payload factory mediator.
Content of the registry resource looks like bellow.
<ns:testMethod xmlns:ns="http://example.com">
<xs:xmlBody xmlns:xs="http://example.com"><![CDATA[$1]]></xs:xmlBody>
<xs:sessionId xmlns:xs="http://example.com">$2</xs:sessionId>
</ns:testMethod>
You can test the scenario by enabling wirelogs for ESB[2].
Here I have hosted a simple axis2 service in WSO2 AS for testing. Here is the wirelog output.
[2016-02-24 19:02:24,696] DEBUG - wire << "POST /services/Hello HTTP/1.1[\r][\n]"
[2016-02-24 19:02:24,696] DEBUG - wire << "Content-Type: application/soap+xml; charset=UTF-8; action="urn:mediate"[\r][\n]"
[2016-02-24 19:02:24,696] DEBUG - wire << "Transfer-Encoding: chunked[\r][\n]"
[2016-02-24 19:02:24,696] DEBUG - wire << "Host: 127.0.0.1:9763[\r][\n]"
[2016-02-24 19:02:24,697] DEBUG - wire << "Connection: Keep-Alive[\r][\n]"
[2016-02-24 19:02:24,697] DEBUG - wire << "User-Agent: Synapse-PT-HttpComponents-NIO[\r][\n]"
[2016-02-24 19:02:24,697] DEBUG - wire << "[\r][\n]"
[2016-02-24 19:02:24,697] DEBUG - wire << "180[\r][\n]"
[2016-02-24 19:02:24,697] DEBUG - wire << "<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"><soapenv:Body><ns:testMethod xmlns:ns="http://example.com"><xs:xmlBody xmlns:xs="http://example.com"><![CDATA[<sample><test>MyData</test></sample>]]></xs:xmlBody><xs:sessionId xmlns:xs="http://example.com">1</xs:sessionId></ns:testMethod></soapenv:Body></soapenv:Envelope>[\r][\n]"
[2016-02-24 19:02:24,697] DEBUG - wire << "0[\r][\n]"
[2016-02-24 19:02:24,697] DEBUG - wire << "[\r][\n]"
Here you can find the defined registry resource with content type as text/xml registry resource
[2] https://docs.wso2.com/display/ESB490/Setting+Up+Logging

Related

WSO2 SOAP reqest

I'm send soap reqest to microservice and in respond I get this.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">SOAP-ENV:Client</faultcode>
<faultstring>An error was detected in the Web Service request. (10894)</faultstring>
<detail>
<ns1:FaultDetail xmlns:ns1="urn:soap-fault:details">
<errorMessage>Error in SOAP Envelope: Content length must be specified. (10913)</errorMessage>
<requestID>----</requestID>
</ns1:FaultDetail>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
I create my soap envelope in payloadFactory.
<payloadFactory description="Set ARGS for CALL" media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:xyz:zyz">
<soapenv:Header/>
<soapenv:Body>
...
</soapenv:Body>
</soapenv:Envelope>
</format>
<args>
...
</args>
</payloadFactory>
Next I send this to microservice. Micro service work on SOAP 1.1. I'm don't attach content lenght because I do not know how.
After the PL factory and before sending the request try setting the following properties.
<property name="DISABLE_CHUNKING" value="true" scope="axis2" />
<property name="messageType" value="text/xml" scope="axis2" type="STRING"/>

WSO2 APIM - JSON to SOAP out sequence not works , return empty value between the SOAP parameter arguments

I tried the following codes in mediation in WSO2 server
Following code for insequence mediation
<sequence name="SOAPtoJSON" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<log level="custom" separator=",">
<property name="TRACE" value="Global Mediation Extension"/>
</log>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
The above insequence works fine and converts the input from SOAP to JSON and forward it to the endpoint.
The SOAP request given to the WSO2 Server via WSO2 Server API Console was,
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:ecomreceipt">
<soapenv:Header/>
<soapenv:Body>
<validatepassbook xmlns="https://10.122.0.32:8243/gpp20038/1.0.0/">
<Mode>$1</Mode>
<Action>$2</Action>
<Attribute>$3</Attribute>
</validatepassbook>
</soapenv:Body>
And then, I logged the request from the WSO2 Server in the endpoint, log shows the following
{"validatepassbook":{"#encodingStyle":"http://schemas.xmlsoap.org/soap/encoding/","Mode":{"#type":"xsd:string","$":"zmzIf0CMfm5ta8lg5xc6Bj1tOEEljipbbrbX2Ph8XFxGyGl5T4vhzzmLIpNuSh6W"},"Action":{"#type":"xsd:string","$":"KGI1718SGS439-KGI14306-SGS3"},"Attribute":{"#type":"xsd:string","$":7904045393}}}
Following code for outsequence mediation
<sequence name="JSONtoSOAP" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<payloadFactory media-type="xml">
<format>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://ws.cdyne.com/PhoneVerify/query">
<SOAP-ENV:Body>
<ns1:CheckPhoneNumbers>
<ns1:PhoneNumbers>
<ns1:string>$1</ns1:string>
</ns1:PhoneNumbers>
<ns1:LicenseKey>$2</ns1:LicenseKey>
</ns1:CheckPhoneNumbers>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
</format>
<args>
<arg evaluator="xml" expression="//request/PhoneNumber"/>
<arg evaluator="xml" expression="//request/LicenseKey"/>
</args>
</payloadFactory>
<property name="messageType" scope="axis2" type="STRING" value="application/soap+xml"/>
And then, I logged the respond that to be sent to WSO2 Server in the endpoint, log shows the following
"{\"request\":{\"PhoneNumber\":\"18006785432\",\"LicenseKey\":\"0\"}}"
And then, I got the output in WSO2 Server API Console was,
Response Body
<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://ws.cdyne.com/PhoneVerify/query"><SOAP-ENV:Body><ns1:CheckPhoneNumbers><ns1:PhoneNumbers><ns1:string/></ns1:PhoneNumbers><ns1:LicenseKey/></ns1:CheckPhoneNumbers></SOAP-ENV:Body></SOAP-ENV:Envelope>
The above response with empty values , but I expect like following reponse
<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://ws.cdyne.com/PhoneVerify/query"><SOAP-ENV:Body><ns1:CheckPhoneNumbers><ns1:PhoneNumbers><ns1:string/>18006785432</ns1:PhoneNumbers><ns1:LicenseKey>0</ns1:LicenseKey></ns1:CheckPhoneNumbers></SOAP-ENV:Body></SOAP-ENV:Envelope>

wso2esb iterate throught wso2dss result

I want to write next target sequence of actions:
1. call DSS to receive a list of customers
2. enrich each customer's by separate call another DSS service.
So, I thought I should call callout mediator and then iterate it's result using iterator. But I can't understand what should I write in the iterator.
And another question - am I right, that the result of each iteration will be attached under the 'customer' tag?
Details:
XML which returned from DSS is next:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<customers xmlns="crm.crm.crm">
<customer>
<customerId>1</customerId>
<name>Customer #1</name>
<birthdate>2017-01-15T14:54:12.000+03:00</birthdate>
</customer>
</customers>
</soapenv:Body>
</soapenv:Envelope>
Sequence:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="BatchSequence" statistics="enable" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<log description="">
<property name="text" value="Start batch seq"/>
</log>
<payloadFactory description="create dss request" media-type="xml">
<format>
<soapenv:Envelope xmlns:crm="crm.crm.crm" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<crm:getCustomers>
<crm:batchSize>3</crm:batchSize>
</crm:getCustomers>
</soapenv:Body>
</soapenv:Envelope>
</format>
<args/>
</payloadFactory>
<callout action="urn:getCustomers" description="dss: main object" initAxis2ClientOptions="false" serviceURL="http://192.168.3.32:9765/services/CrmDataService?wsdl">
<source type="envelope"/>
<target key="customers"/>
</callout>
<log description="">
<property expression="get-property('customers')" name="text"/>
</log>
<iterate description="Enrich customers" expression="/soapenv:Envelope/soapenv:Body/customers/customer" id="iterateId" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<target>
<sequence>
<property description="customerId" expression="/customerId" name="customerID" scope="default" type="STRING"/>
<log description="">
<property expression="get-property('customerID')" name="text"/>
</log>
</sequence>
</target>
</iterate>
<log description="">
<property name="text" value="End batch seq"/>
</log>
</sequence>
output:
[2017-01-27 10:17:17,371] INFO - LogMediator To: , MessageID: urn:uuid:d628e361-beb8-4c26-b06d-3901227ad76a, Direction: request, text = Start batch seq
[2017-01-27 10:17:18,558] INFO - LogMediator To: , MessageID: urn:uuid:d628e361-beb8-4c26-b06d-3901227ad76a, Direction: request, text = 1Customer #12017-01-15T14:54:12.000+03:002Customer #22016-12-16T14:54:20.000+03:003Customer #32016-10-27T14:54:21.000+03:00
[2017-01-27 10:17:18,559] WARN - RuntimeStatisticCollector Events occur after event collection is finished, event - urn_uuid_d628e361-beb8-4c26-b06d-3901227ad7
6a231160071781262
Update 1
Some working code. Not sure that this is correct, because I'm a little bit confusing for a PayloadFactory here..
<payloadFactory description="" media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>$1</soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg evaluator="xml" expression="get-property('customers')"/>
</args>
</payloadFactory>
<iterate continueParent="true" description="" expression="$body/crm:customers/crm:customer" sequential="true" xmlns:crm="crm.crm.crm">
<target>
<sequence>
<property expression="//crm:customerId" name="customerID" scope="default" type="STRING"/>
<log>
<property expression="get-property('customerID')" name="text"/>
</log>
</sequence>
</target>
</iterate>
Update 2
I figured a main problem - callout mediator doesnt' put response to the envelope context(if I understand right). So, we can't use just property to link it with iterator, so, in this case we should link them using smth like Payload factory. Not very usifull
If smbdy knows how to do it more simple(dirrect passing property to the iterator) - pls write to me.
Solution - to use Call medator. Works fine.
thanks to all!
xml nodes in the dss response belongs to a namespace "crm.crm.crm" and you must refer it in your xpath
with iterate mediatior, if you want to preserve source payload, you must use an attribute named preservePayload="true" and tell where the xml framents must be attached with the attribute attachPath ortherwise, inside interate's sequence, you will only have your xml fragment in the soap body
This is a sample that works without preserving source payload :
<iterate xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:crm="crm.crm.crm" expression="$body/crm:customers/crm:customer" id="iterateId">
<target>
<sequence>
<property expression="$body/crm:customer/crm:customerId" name="customerID" scope="default" type="STRING"/>
<log>
<property expression="get-property('customerID')" name="text"/>
</log>
</sequence>
</target>
</iterate>
By default, mediators after iterate will not be executed. If you want to continue the mediation, use attribute continueParent="true"

SOAP messages are not sent using wso2 ESB REST API

I'm trying to expose SOAP backend as REST API using wso2 ESB. I'm using payload factory to send the soap body message, but it doesn't work.
This is my API resource in wso2 esb code :
<?xml version="1.0" encoding="UTF-8"?>
<api context="/akademik" name="SampleAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET" uri-template="/students?symbol={symbol}">
<inSequence>
<log level="custom">
<property expression="$url:symbol" name="symbol"/>
</log>
<payloadFactory media-type="xml">
<format>
<soapenv:Envelope xmlns:sem="http://semogabisa.te.net/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<sem:sayHi>
<arg0>$1</arg0>
</sem:sayHi>
</soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg evaluator="xml" expression="$url:symbol"/>
</args>
</payloadFactory>
<header scope="default">
<m:complexHeader xmlns:m="http://org.synapse.example">
<m:property key="Content-Type" value="application/xml"/>
</m:complexHeader>
</header>
<send>
<endpoint>
<address format="soap11" uri="http://localhost:8084/HelloWorld"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence/>
</resource>
Soap messages are not sent to the backend web service, it says null.
I've test the backend service with SOAPUI with same soap envelope format and it's working
I think you make some mistake on the header mediator. "HelloWorld" back end service didn't need the SOAP header based on your SOAP UI request. so remove the header mediator.
Select Synapse if you want to manipulate SOAP headers. Select Transport if you want to manipulate HTTP headers.
And it's seems back end is SOAP11, SOAP11 type is "text/xml". Your may need set this property.
<property name="messageType" value="text/xml" scope="axis2"/>
When you send message out from ESB, you need set property "messageType", then ESB will formatter the message that match back end required.
You may probably need this property, if you found ESB append some context to your back end URI when send message to back end.
<property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
Good Tips:
Please open your "synapse.transport.http.wire" as DEBUG, this will output every message in and out from ESB. This log will including HTTP header and body. After you got the wire log, you can compare wire log with your SOAPUI request, then find out which part is wrong.
https://docs.wso2.com/display/ESB481/Setting+Up+Logging

wso2 esb service endpoint in request

I am getting service endpoint as input SOAP request to WSO2 esb, based
on that need to send payload data to that endpoint and response to
client. Please advise how to send payload to that endpoint. I tried
Header mediator but no luck. Following is the SOAP XML request coming
to ESB which has service endpoint reference, under property element.
<soapenv:Envelope
xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
<soapenv:Body> <resources> <resource>
<properties>
<property name="location" value="http://localhost:8280/services/echo.echoHttpSoap11Endpoint"/>
</properties> </resource> </resources> </soapenv:Body> </soapenv:Envelope>
First retrieve the address value using the expression "//properties/property/#value". Then set the To address of the header mediator and send the message.
<property name="address" expression="//properties/property/#value"/>
<header name="To" expression="get-property('address')"/>
<payloadFactory>
<format>
<p:echoInt xmlns:p="http://echo.services.core.carbon.wso2.org">
<in xmlns="">$1</in>
</p:echoInt>
</format>
<args>
<arg value="1"/>
</args>
</payloadFactory>
<send/>