I am using java soap request and response in my code. I am getting the request and response properly.
But I am not able to iterate the response
Please see my response and code used to iterate below. Please help me to resolve this issue.
Response
<?xml version="1.0" encoding="utf-16"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetUserResponse xmlns="http://XXXX.com/XXXXXXXX.XXXXXXX.WS">
<GetUserResult>
user
<PersonID>111113</PersonID>
<Username>0987654321</Username>
<Password />
<FwyMember>Y</FwyMember>
<WebMember>Y</WebMember>
<FirstName>Mohamed</FirstName>
<Tier>firstclass</Tier>
<CountryOfResidence>IN</CountryOfResidence>
<PreferencesChanged>false</PreferencesChanged>
<FamilyRelationship />
<Title>Mr</Title>
<MiddleName />
........ continue like this
Java code
SOAPBody responseBody = response.getSOAPBody();
QName bodyName1 = new QName("http://XXXX.com/XXXXXXXX.XXXXXXX.WS","GetUserResponse");
java.util.Iterator iterator = responseBody.getChildElements(bodyName1);
while (iterator.hasNext()) {
SOAPBodyElement responseElement = (SOAPBodyElement)iterator.next();
String val = responseElement.getValue();
System.out.println("The values are "+val);
}
There is only one GetUserResponse element below Body. getChildElements only gets child elements, as opposed to descendant elements. You must first reach GetUserResponse and then iterate over its children.
Related
I have the following XML file (SOAP response) that I'm trying to map to a Java object :
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:AffaireByTiersResponse xmlns:ns2="http://service.hibernate.com/">
<Affaire>
<code_produit>Cred</code_produit>
<id>1</id>
<montant_fin>2000.0</montant_fin>
<id_tier>1</id_tier>
</Affaire>
<Affaire>
<code_produit>Cred</code_produit>
<id>2</id>
<montant_fin>25000.0</montant_fin>
<id_tier>1</id_tier>
</Affaire>
</ns2:AffaireByTiersResponse>
</soap:Body>
</soap:Envelope>
in order to marshall the file I need to keep only the tag <AffaireByTiersResponse> as root element and change its name to <Affaires>.
What is the best way to do this?
Extracting the underlying content from the SOAP envelop can be done using javax.xml.soap.MessageFactory.
String example = new String(Files.readAllBytes(Paths.get("input.xml")), StandardCharsets.UTF_8);
SOAPMessage message = MessageFactory.newInstance().createMessage(null,
new ByteArrayInputStream(example.getBytes()));
Document doc = message.getSOAPBody().extractContentAsDocument();
Element root = doc.getDocumentElement();
The root node can then be renamed
doc.renameNode(root, root.getNamespaceURI(), "Affaires");
and this document can then be passed into the JAXB unmarshaller
Unmarshaller unmarshaller = JAXBContext.newInstance(Affaires.class).createUnmarshaller();
Affaires farm = (Affaires) unmarshaller.unmarshal(doc);
So I have this SOAP Message:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV=" http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<pid:pid xmlns:pid="pt:ulisboa:tecnico:sdis:store:ws">carla</pid:pid> </SOAP-ENV:Header> <S:Body><ns2:
loadResponse xmlns:ns2="urn:pt:ulisboa:tecnico:sdis:store:ws"/></S:Body>
</S:Envelope>
So you see pid="carla"
But when I get all the attributes:
Iterator iter = hd.extractAllHeaderElements();
while(iter.hasNext()){
System.out.println(iter.next());
}
All it prints is:
[pid:pid: null]
Any ideas why it isn't "carla"?
I'm doing all this processing in the handlers.
I am pretty new in the WebServices interrogation using Java and I have the following problem.
I have a web service that provide to me a getConfigSettings() method that, by its response, say to me some informations including whether a user is enabled or not on a certain service (it say if the couple username and password is correct and if the user can log into the system).
In particular I have the following REQUEST of the getConfigSettings() method:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:getConfigSettings>
<!--Optional:-->
<tem:login>name.surname</tem:login>
<!--Optional:-->
<tem:password>rightPawssword</tem:password>
<!--Optional:-->
<tem:ipAddress>144.44.55.4</tem:ipAddress>
<!--Optional:-->
<tem:clientVersion>1</tem:clientVersion>
<!--Optional:-->
<tem:lastUpdateTime>2</tem:lastUpdateTime>
</tem:getConfigSettings>
</soapenv:Body>
</soapenv:Envelope>
And this is the webservice RESPONSE in case the couple username and password is correct and the user can log into the system:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<getConfigSettingsResponse xmlns="http://tempuri.org/">
<getConfigSettingsResult>
<![CDATA[
<root>
<status>
<id>0</id>
<message></message>
</status>
<drivers>
<drive id="tokenId 11">
<shared-secret>Shared 11</shared-secret>
<encoding>false</encoding>
<compression />
</drive>
<drive id="tokenId 2 ">
<shared-secret>Shared 2 </shared-secret>
<encoding>false</encoding>
<compression>false</compression>
</drive>
</drivers>
</root>
]]>
</getConfigSettingsResult>
</getConfigSettingsResponse>
</s:Body>
</s:Envelope>
In this response the important section is:
<status>
<id>0</id>
<message></message>
</status>
because <id>0</id> means that the user can log into the system
On the contrary if the couple username and password is incorrect I will obtain the following RESPONSE:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<getConfigSettingsResponse xmlns="http://tempuri.org/">
<getConfigSettingsResult><![CDATA[<root>
<status>
<id>-1</id>
<message>Login or password incorrect</message>
</status>
</root>]]></getConfigSettingsResult>
</getConfigSettingsResponse>
</s:Body>
</s:Envelope>
As you can see in this case I have that <id>-1</id> (that represent a situation of error) and in the message tag it specify the type of error occurred.
Ok, now I have to create a Java method that call this getConfigSettings() method passing to it the requested 5 parameters: login, password, ipAddress, clientVersion and lastUpdateTime (also if at this stage the only important parameters are login and password, the others can be whatever...)
And now I have no idea about how do it.
In my project there is another method that call another request report of the same web services that is:
public String getVersion() {
java.net.URL url = null;
java.net.URLConnection conn = null;
java.io.BufferedReader rd = null;
String soapResponse = "";
String risultato = "";
// SOAP ENVELOP for the request:
String soapRequest;
soapRequest = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tem=\"http://tempuri.org/\">" + "<soapenv:Header/>" + "<soapenv:Body> " + "<tem:getVersion/>" + "</soapenv:Body>" + "</soapenv:Envelope>";
try {
// Try to open a connection
url = new java.net.URL(_webServiceUrl);
conn = url.openConnection();
// Set the necessary header fields
conn.setRequestProperty("SOAPAction", "http://tempuri.org/IMyService/getVersion");
conn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
conn.setDoOutput(true);
// Send the request:
java.io.OutputStreamWriter wr = new java.io.OutputStreamWriter(conn.getOutputStream());
wr.write(soapRequest);
wr.flush();
// Read the response
rd = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream()));
// Put the entire response into the soapResponse variable:
String line;
while ((line = rd.readLine()) != null) {
//System.out.println(line);
soapResponse = soapResponse + line + System.getProperty("line.separator");
}
rd.close();
// PERFORM SOME ELABORATION ON THE RESPONSE
..........................................
..........................................
..........................................
..........................................
return risultato;
}
Looking at this working method it seems to me that do something like that:
It create a String object that contain the SOAP Envelop for my request.
Try to connect to my WebService.
Then Set the necessary header fields (and this is not clear for me, what exactly mean? and what is tempuri?), what exactly do the following lines:
conn.setRequestProperty("SOAPAction", "http://tempuri.org/IMyService/getVersion");
conn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
conn.setDoOutput(true);
Send my prepared request to the WebService
Obtain the response and put it into my String soapResponse variable
This is what I want to obtain creating the other authentication() method, I have to create the SOAP Envelop using the previous parameters, send it to the webservice and obtain the SOAP response.
I think that my main problem is how to create the right String soapRequest object that use the parameter to do that.
I'm using jpachube and am running into problems with .POST on creatDatastream. I am getting POST error 400, and the following details from COSM's debug tool:
{"title":"JSON Parser Error","errors":"lexical error: invalid char in json text. <? xmlversion=\"1.0\"encoding=\"U"}
My XML request body from the COSM debug tool is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<eeml xmlns="http://www.eeml.org/xsd/005"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5" xsi:schemaLocation="http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd"><environment><data id="0">
<tag>CPU</tag>
<current_value>0.0</current_value>
</data>
</environment>
</eeml>
COSM's API documentation for what the xml request body should look like is as follows:
<eeml xmlns="http://www.eeml.org/xsd/0.5.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema- instance" version="0.5.1" xsi:schemaLocation="http://www.eeml.org/xsd/0.5.1 http://www.eeml.org/xsd/0.5.1/0.5.1.xsd">
<environment>
<data id="23">
<tag>apple</tag>
<tag>jag</tag>
<tag>tag</tag>
<tag>lag</tag>
<current_value>11</current_value>
<max_value>211.0</max_value>
<min_value>7.0</min_value>
<unit type="conversionBasedUnits" symbol="symbol">label</unit>
</data>
</environment>
The only difference I found was the version #, but I made that switch in the code already and got the same error.
I thought for the v2 of the COSM API was set up so xml and JSON are interchangeable but it converts everything to JSON.
The error is coming from this method call in Pachube.java
public boolean createDatastream(int feed, String s) throws PachubeException {
HttpRequest hr = new HttpRequest("http://api.cosm.com/v2/feeds/"
+ feed + "/datastreams/");
hr.setMethod(HttpMethod.POST);
hr.addHeaderItem("X-PachubeApiKey", this.API_KEY);
hr.setBody(s);
HttpResponse g = this.client.send(hr);
if (g.getHeaderItem("Status").equals("HTTP/1.1 201 Created")) {
return true;
} else {
throw new PachubeException(g.getHeaderItem("Status"));
}
}
Any input appreciated.
Day two...
Modified the createDatastream method using input from bjpirt (much thanks). Method looks like this
public boolean createDatastream(int feed, String s) throws PachubeException {
HttpRequest hr = new HttpRequest("http://api.cosm.com/v2/feeds/"
+ feed + "/datastreams.xml");
hr.setMethod(HttpMethod.POST);
hr.addHeaderItem("X-PachubeApiKey", this.API_KEY);
hr.addHeaderItem("Content-Type:", "application/xml");
hr.setBody(s);
HttpResponse g = this.client.send(hr);
if (g.getHeaderItem("Status").equals("HTTP/1.1 201 Created")) {
return true;
} else {
Log.d("create data stream", "prob");
throw new PachubeException(g.getHeaderItem("Status"));
}
}
This throws the following error for .POST on the COSM debug tool (error code 422):
<?xml version="1.0" encoding="UTF-8"?><errors><title>Unprocessable Entity</title> <error>Stream ID has already been taken</error></errors>
So, naturally, I need to get a title on this request. That is done through the toXMLWithWrapper in Data.java
public String toXMLWithWrapper() {
String ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<eeml xmlns=\"http://www.eeml.org/xsd/005\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"5\" xsi:schemaLocation=\"http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd\"><environment>";
ret = ret + ">\n\t<title>" + "cosm app" + "</title>\n\t";//inserted this line to add title
ret = ret + this.toXML() + "</environment></eeml>";
return ret;
}
And the request body looks like (from COSM debug tool):
<?xml version="1.0" encoding="UTF-8"?>
<eeml xmlns="http://www.eeml.org/xsd/005" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5" xsi:schemaLocation="http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd"><environment>
<title>cosm app</title>
<data id="0">
<tag>CPU</tag>
<current_value >0.0</current_value>
</data></environment></eeml>
This comes back as error code 500 (ouch!)
Response body is
<?xml version="1.0" encoding="UTF-8"?><errors><title>Oops, something's broken</title> <error>We've been unable to complete your request due to a problem with our server</error></errors>
day three
it was pointed out that there was a problem with the xml (see below). I fixed the typo and I'm back to a 422 error. So, looking more closely at the response body I thought maybe that there was something wrong with the data stream. I delete all of the datastreams in the feed, create a new feed, and I get exactly ONE AWESOME HTTP:/1.1 201 - happy, right? Wrong, after the first .POST I get nothing. When I turn the app off and then back on, I'm back to 422 error and the same response body "Stream ID has already been taken". Yikes!
It seems like the xml may be invalid.
The opening <environment> node seems to be closed twice <environment>>
The 422 is probably because you are trying to POST to an existing feed.
To update a feed you need to send a PUT request.
See the Updating a feed docs
The clue is that the system looks like it's expecting json but you're feeding it XML. The default for the v2 api is json, so you'll need to make sure that you're including XML in the URL, e.g:
https://api.cosm.com/v2/feeds/113/datastreams.json
Alternatively, you can set a content type header on the request to indicate this:
Content-Type: application/xml
Why can I set a faulString, but can't I set a custom fault code in a SOAPFault? When I throw the exception, the text "Code X" does not appear in the SoapFaultException. Someone could tell me why? Thanks.
SOAPFault soapFault = SOAPFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL).createFault();
soapFault.setFaultString("String Y")
soapFault.setFaultCode("Code X");
throw new SOAPFaultException(soapFault);
It is possible to get the fault code in the soap response with the following example:
String faultString = "String Y";
String faultCodeValue = "Code X";
QName faultCode = new QName("nameSpaceURI", faultCodeValue);
SOAPFault soapFault = null;
try {
soapFault = SOAPFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL).createFault(faultString, faultCode);
throw new javax.xml.ws.soap.SOAPFaultException(soapFault);
} catch (SOAPException e1) {
//
}
I get the following soap fault back:
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope" xmlns="">
<faultcode xmlns:ns0="nameSpaceURI">ns0:Code X</faultcode>
<faultstring>String Y</faultstring>
</S:Fault>
</S:Body>
</S:Envelope>
From documentation:
Fault codes, which given information about the fault, are defined in
the SOAP 1.1 specification. This element is mandatory in SOAP 1.1.
Because the fault code is required to be a QName it is preferable to
use the setFaultCode(Name) form of this method.
faultCode - a String giving the fault code to be set. It must be of
the form "prefix:localName" where the prefix has been defined in a
namespace declaration.
Notice that the fault code your're setting has to be this format: prefix:localName. You're setting: Code X, that is why you do not see it. Use this method and all should be OK.