I have generated a web-service client (JAX-WS) and model from wsdl and xsd. I have problem with namespaces within soap body.
Lets assume we have two classes:
#XmlRootElement(namespace="aNamespace") class A {
#XmlAnyElement(lax = true) Object obj;
}
#XmlRootElement(namespace="bNamespace") class B {...}
The object I want to send is 'a':
A a = new A();
a.obj = new B();
The service I am calling expects either of V1 or V3 requests:
V1
...
<soapenv:Body>
<A xmlns="aNamespace">
<B xmlns="bNamespace">
<B1>...</B1>
<B2>...</B2>
</B>
</A>
</soapenv:Body>
...
V3
...
<soapenv:Body>
<a:A xmlns:a="aNamespace">
<b:B xmlns:b="bNamespace">
<b:B1>...</b:B1>
<b:B2>...</b:B2>
</b:B>
</a:A>
</soapenv:Body>
...
Trying to call the service I see following request generated:
V2
...
<soapenv:Body>
<a:A xmlns:a="aNamespace", xmlns:b="bNamespace">
<b:B>
<b:B1>...</b:B1>
<b:B2>...</b:B2>
</b:B>
</a:A>
</soapenv:Body>
...
And the service returns error.
Can I somehow set a default namespace to B(so that I will see <B xmlns="bNamespace">)?
I solved the problem by marshaling B into DOM object. Then I put the created DOM into A.
B b = new B();
Document bDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
JAXBContext.newInstance(B.class).createMarshaller().marshal(b, bDocument);
A a = new A();
a.obj = bDocument;
It produces some weird result, however the web-service accepts it:
...
<soapenv:Body>
<a:A xmlns:a="aNamespace" xmlns:ab="bNamespace">
<b:B xmlns:b="bNamespace">
<b:B1>...</b:B1>
<b:B2>...</b:B2>
</b:B>
</a:A>
</soapenv:Body>
...
Related
Below scenario bringing in me proper SOAP body but I'm not able to extract it's values using xpath expression
The path expression /*/soap:Body/m:NumberToDollarsResponse/m:NumberToDollarsResult/text() I have formed using this website
https://codebeautify.org/Xpath-Tester
val httpConf = http.baseUrl("https://www.dataaccess.com")
val headerXml = Map("Keep-Alive" -> "115", "Content-Type" -> "application/soap+xml; charset=utf-8")
val soapXmlScn = scenario("make First Soap Call")
.exec(
http("Soap API Call With XML")
.post("/webservicesserver/numberconversion.wso")
.headers(headerXml)
.body(StringBody("""<?xml version="1.0" encoding="utf-8"?>
<soap20:Envelope xmlns:soap20="http://www.w3.org/2003/05/soap-envelope">
<soap20:Body>
<NumberToDollars xmlns="http://www.dataaccess.com/webservicesserver/">
<dNum>45</dNum>
</NumberToDollars>
</soap20:Body>
</soap20:Envelope>"""))
.check(status.is(200))
.check(xpath("""//*/soap:Body/m:NumberToDollarsResponse/m:NumberToDollarsResult/text()""").saveAs("doller_value" ))
)
.exec {
session =>
println("doller value >>>> " + session("doller_value").as[String].toString)
session
}
Response body is
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<m:NumberToDollarsResponse xmlns:m="http://www.dataaccess.com/webservicesserver/">
<m:NumberToDollarsResult>forty five dollars</m:NumberToDollarsResult>
</m:NumberToDollarsResponse>
</soap:Body>
</soap:Envelope>
The error shown on console is
12:22:16.880 [ERROR] i.g.c.a.b.SessionHookBuilder$$anon$1 - 'hook-1' crashed with 'j.u.NoSuchElementException: No attribute named 'doller_value' is defined', forwarding to the next one
namespace List needs to be provided to your xpath check as below and my request working fine. Those namespace URLs are mentioned in your SOAP response xml only
.check(xpath("""//soap:Envelope/soap:Body/m:NumberToDollarsResponse/m:NumberToDollarsResult/text()""", List("soap" -> "http://www.w3.org/2003/05/soap-envelope", "m" -> "http://www.dataaccess.com/webservicesserver/")).findAll.saveAs("doller_value" ))
I'm attempting to call SOAP Web-Service in hybrid app. How should I form SOAP message correctly if the back-end service displays the next error in log:
Caused by: com.ibm.websphere.security.WSSecurityException: Exception
org.apache.axis2.AxisFault: CWWSS7509W: The received SOAP request
message is rejected becasue it does not correctly specify SOAP action
and WS-Addressing action while there is at least one PolicySet
attachment at operation level of the
TestServiceService.TestServicePort service. ocurred while running
action:
com.ibm.ws.wssecurity.handler.WSSecurityConsumerHandler$1#9b5addf6 at
com.ibm.ws.security.context.ContextImpl.runWith(ContextImpl.java:394)
at
com.ibm.ws.wssecurity.platform.websphere.auth.WSSContextImpl.runWith(WSSContextImpl.java:65)
... 35 more
This is content of js file in adapter
function getToken(){
var token = WL.Server.getActiveUser().attributes.LtpaToken;
var fulltoken = "LtpaToken2=" + token;
return fulltoken;
}
function callService(){
WL.Logger.warn("INSIDE callService "+getToken());
var path="checkauth/TestServiceService";
var request=
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:q0="http://provider.ws/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<q0:callService />
</soapenv:Body>
</soapenv:Envelope>;
var input = {
method : 'post',
returnedContentType : 'xml',
path : path,
body: {
content: request.toString(),
contentType: 'text/xml; charset=utf-8',
},
headers: {"Cookie": getToken()}
};
var result= WL.Server.invokeHttp(input);
return result;
}
This is SOAP Envelope which was displayed via TCP/IP Monitor:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<s:Security xmlns:s="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:w2="http://www.ibm.com/websphere/appserver/tokentype" soapenv:mustUnderstand="1">
<u:Timestamp>
<u:Created>2015-08-10T13:18:56.644Z</u:Created>
</u:Timestamp>
<s:BinarySecurityToken ValueType="w2:LTPAv2" u:Id="ltpa_20">dt8G5gZ9PpZ/Ea5oXr6EQd8dpmfXKiqeXiShPlpSWntK59hUzyoDNX9TKq1nFLfxUEJyJdjMxoG7EVxw8Q1zhyZdYhTXnsMkNVqScvSsPpX7ln/ad+/WAHqaaFymD8XtVEsjOlezQDarPaUmnKAQRUSrLkRnL5B1MoCclTe129Oojg8o+hACgDKjuvPnvL8jaf45wNiou6Il5ZOayBcoHpNehI7i2hADa4fTKzX/T69OPnsZOyWYrNosdezNd24b61vs85k2YK26rLTp5dkEp8f3mwKZBwOOK4z1wQdiAXJf6kQvzR22SfFitbJA5MStlBcovHAvB5T+J5Ip80/kI5BPa2ogoufd9HZAdKTNII8cHpHBN2Ub/+atzg1L7EhIWuzO1BPI62KoU/hPqAHn3uGCGrbIILesKx0TPvlgmU4Bg54H9prC0I8hgXbO1HLuz4M5DNE5ASFbH0W3LJ/UU7BGXJs6iJmfAfJtQ+ip5ZFHlLItZA+ca2LkVWmyD/xKVxyxHE1uDz8zV/CfV9Km0T+8FTA0Cfi/PIb5KiAagdrmqtw6GuJDbSCsC3sdh21G/cA3Y0p/f+rhDw8m/e17y1cEuq9HOBharwn7ET3wO30V4D4rGoLhd4QsN6X1z89gZmZVaI6J9urpPAEiSndmyQ==</s:BinarySecurityToken>
</s:Security>
<wsa:To>http://X.X.X.X:9082/checkauth/TestServiceService</wsa:To>
<wsa:MessageID>urn:uuid:5d1f8656-5550-40d2-9f39-c58f57279489</wsa:MessageID>
<wsa:Action>http://provider.ws/TestServiceDelegate/callServiceRequest</wsa:Action>
</soapenv:Header>
<soapenv:Body>
<ns2:callService xmlns:ns2="http://provider.ws/"/>
</soapenv:Body></soapenv:Envelope>
The body consists of a single line, and this makes the scenario a peculiar one, as well as raises a question is this is meant to work at all.
I can suggest two things:
You can attempt to parse your WSDL file with the SOAPUI application; it should show you how the SOAP envelope is supposed to look like
Use the Service Discovery feature in MobileFirst Studio that can generate the adapter for you with a ready SOAP envelope. Read more how to use this feature, here: http://www-01.ibm.com/support/knowledgecenter/SSHS8R_7.0.0/com.ibm.worklight.dev.doc/dev/c_using_service_discovery_wizard_to_explore_backend-services.html
I'm trying to do mock response based on the request.
With a request like that:
<soapenv:Body>
<con:person>
<person>
<name>John</name>
<age>18</age>
</person>
</con:person>
</soapenv:Body>
and a reponse like that
<soapenv:Body>
<con:result>
<person>
<name>?</name>
<age>?</age>
<country>?</country>
<city>?</city>
</person>
</con:result>
</soapenv:Body>
I can use elements from the request to take what i want in database and create the response.
But when i have a request with many person like that
<soapenv:Body>
<con:person>
<person>
<name>John</name>
<age>18</age>
</person>
<person>
<name>Doe</name>
<age>50</age>
</person>
</con:person>
</soapenv:Body>
I don't know how i can take all data from the request and how i can use them to create a response like that:
<soapenv:Body>
<con:result>
<person>
<name>John</name>
<age>18</age>
<country>France</country>
<city>Paris</city>
</person>
<person>
<name>Doe</name>
<age>50</age>
<country>Spain</country>
<city>Madrid</city>
</person>
</con:result>
</soapenv:Body>
With the same number of person in the request and in the response.
I hope i was clear and i thank you for your answers.
I managed to do something similar. First, I defined my mock response object as:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:stac="stackOverflow.question">
<soapenv:Header/>
<soapenv:Body>
<stac:result>
${personElements}
</stac:result>
</soapenv:Body>
</soapenv:Envelope>
I then created the content for ${personElements} using this Groovy script:
import groovy.xml.MarkupBuilder
// An array from which county and city will be drawn randomly
def countryArray = [["Australia", "Perth"],
["Spain", "Madrid"],
["England","London"],
["Brazil", "Rio"]]
def random = new Random()
// create XmlHolder for request content
def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
// Get the name and age values from the request
def requestItems = holder.getNodeValues( "//*:person/*:person/descendant::*")
def writer = new StringWriter()
def personElements = new MarkupBuilder(writer)
// Build the response elements
for (int index = 0; index < requestItems.size() - 1; index += 2) {
personElements.'stac:person'() {
'stac:name'(requestItems[index])
'stac:age'(requestItems[index+1])
// Choose a random county and city from the array
def randomIndex = random.nextInt(countryArray.size())
'stac:country'(countryArray[randomIndex][0])
'stac:city'(countryArray[randomIndex][1])
}
}
// Add the newly created elements to the response
context.personElements = writer.toString()
This gave me a response like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:stac="stackOverflow.question">
<soapenv:Header/>
<soapenv:Body>
<stac:result>
<stac:person>
<stac:name>Dolly Bonkers</stac:name>
<stac:age>42</stac:age>
<stac:country>Brazil</stac:country>
<stac:city>Rio</stac:city>
</stac:person>
<stac:person>
<stac:name>Mary Poppins</stac:name>
<stac:age>82</stac:age>
<stac:country>England</stac:country>
<stac:city>London</stac:city>
</stac:person>
<stac:person>
<stac:name>Bilbo Baggins</stac:name>
<stac:age>102</stac:age>
<stac:country>Australia</stac:country>
<stac:city>Perth</stac:city>
</stac:person>
<stac:person>
<stac:name>Johnny Hardcase</stac:name>
<stac:age>22</stac:age>
<stac:country>Spain</stac:country>
<stac:city>Madrid</stac:city>
</stac:person>
</stac:result>
</soapenv:Body>
</soapenv:Envelope>
The script just takes random city and country values from a small array but you could come up with something better if you wanted consistent responses for certain names.
I want to make a post request in Scala to this API http://api.atinternet-solutions.com/toolbox/reporting.asmx
I first did it with a curl like this :
curl -X POST -T post.txt -H "Content-Type: application/soap+xml; charset=utf-8" http://api.atinternet-solutions.com/toolbox/reporting.asmx -v
and I got what I expected.
Now I want to call the API programatically with a simple HttpClient
val httpClient = new DefaultHttpClient()
def postRequest=new HttpPost("https://api.atinternet-solutions.com/toolbox/reporting.asmx")
postRequest.addHeader("Content-Type","application/soap+xml ; charset=utf-8")
postRequest.addHeader("SOAPAction","\"http://www.xiti.com/queryReport\"")
val file=new File("post.txt")
val fe=new FileEntity(file,"application/soap+xml;charset=utf-8")
postRequest.setEntity(fe)
val httpResponse=httpClient.execute(postRequest)
println(httpResponse.getStatusLine.toString)
val rspStr=Source.createBufferedSource(httpResponse.getEntity.getContent).mkString
println(rspStr)
but I get an HTTP/1.1 500 Internal Server Error
and printing the rspStr yields
"?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><soap:Code><soap:Value>soap:Receiver</soap:Value></soap:Code><soap:Reason><soap:Text xml:lang="en">Server was unable to process request. ---> Root element is missing.</soap:Text></soap:Reason><soap:Detail /></soap:Fault></soap:Body></soap:Envelope"
The post.txt looks like below, except I set the good information instead.
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Header>
<NXHeader xmlns="http://www.xiti.com/">
<GUID>string</GUID>
<SecurityKey>string</SecurityKey>
<Site>int</Site>
</NXHeader>
</soap12:Header>
<soap12:Body>
<queryReport xmlns="http://www.xiti.com/">
<startDate>int</startDate>
<endDate>int</endDate>
<query>string</query>
<param>string</param>
<typereport>XML or CSV</typereport>
</queryReport>
</soap12:Body>
</soap12:Envelope>
The curl action which is working is done from my scala project directory. I printed post.txt in scala and got the good content.
I cannot figure out what is going wrong. Thank you for your help
I tried your call with the dispatch library.
This is my code
import dispatch._
import java.io.File
object ToolBox {
val endpoint = url("https://api.atinternet-solutions.com/toolbox/reporting.asmx").POST
.addHeader("Content-Type","application/soap+xml ; charset=utf-8")
.addHeader("SOAPAction",""" "http://www.xiti.com/queryReport" """)
def report = Http( endpoint <<< new File("post.txt") > as.xml.Elem)
def tryReport = {
val res = report.either
for {
ex <- res.left
} yield "Something got wrong " + ex.getMessage
}
}
The service replies with a status 500 like you, but the faultString in the response xml is: A parameter is missing in your NXHeader or you have a namespace issue.
Is it what you would expect, since the post.txt body contains only the placeholders from the query report example, instead of real parameters?
I found what was going wrong.
Replace
def postRequest
by
val postRequest.
Tks again
Am trying to query netsuite api for currencies. The following soap request works for me in SOAP UI client. But i am having a hard time trying to get the same working with ruby's savon gem version 0.9.7.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:messages_2012_2.platform.webservices.netsuite.com" xmlns:urn1="urn:core_2012_2.platform.webservices.netsuite.com">
<soapenv:Header>
<urn:passport>
<urn1:email>xxx#abc.com</urn1:email>
<urn1:password>xxx</urn1:password>
<urn1:account>xxx</urn1:account>
</urn:passport>
</soapenv:Header>
<soapenv:Body>
<urn:getAll>
<urn:record recordType="currency"/>
</urn:getAll>
</soapenv:Body>
</soapenv:Envelope>
Basically i am not able to set the attribute on the urn:record element. The following is not working:
response = client.request :urn, :get_all do
soap.body = { "urn:record" => { :attributes! => { "recordType" => "currency" } } }
end
Please advise.
As explained on http://savonrb.com the key in the attributes! hash has to match the XML tag. You want to write something like this:
response = client.request :urn, :get_all do
soap.body = {'urn:record'=>'',
:attributes!=>{'urn:record'=>{'recordType'=>'currency'}}
}
end
Please let us know whether this solves it for you.
Double-check the raw soap request. :get_all may need to be "getAll" to have savon take you literally; it may be changing it to GetAll
In new versioin of savon you can place :attributes in the local context for the operation tag:
#interaction_client.call(:retrieve_interaction, message: message_hash, :attributes => { 'attachmentInfo' => include_attachments.to_s })
In this case, the attachmentInfo attribute will be placed into the main operation tag linked with operation, in this example this would be the ns:RetrieveInteractionRequest tag.
Please note that the syntax does not contains the exclamation mark.