multiple response parameters in apache axis are not all not returned
Hi all,
I'm having an issue parsing a soap response message with multiple output
parameters:
An example of the soap response msg (notice it contains 4 sub nodes)
Code:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<error xmlns="http://testcase/itpserver/wsdl">OK</error>
<outKeyValues xmlns="http://testcase/itpserver/wsdl">
<KeyValue>
<key>Email</key>
<value/>
</KeyValue>
<KeyValue>
<key>Printer</key>
<value/>
</KeyValue>
</outKeyValues>
<outDocuments xmlns="http://testcase/itpserver/wsdl">
<Doc>
<id>PDF</id>
<content>JVBERi0xLjQNJf////8NMSAwIG9iag08PA...</content>
</Doc>
</outDocuments>
<progress xmlns="http://testcase/itpserver/wsdl"/>
</soap:Body>
</soap:Envelope>
Problem is that the call.getOutputParams method returns a Map with only
the first node directly under the soap body. I would expect that all 4 the
subnodes are present in the returned Map. (the errorNode is in the Map)
I have looked in to the source of the axis code how that map is filled and
descovered the following:
// call.invoke ==> soapenvelope.getfirstbody ==> body.getfirstboy ==>
getChildren().get(0)!!! (see SOAPBODY.getFirstBody)
==> this confirms the result of my test case
I expected however that the map contains ALL output parameters from the
response body.
Does anybody know what is going on here, why not put all these params in
the Map, or is it a bug???
The test code:
Code:
package client;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.RemoteException;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import javax.xml.rpc.ServiceException;
import org.apache.axis.AxisFault;
import org.apache.axis.Message;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.description.ParameterDesc;
import org.apache.axis.utils.XMLUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import client.util.Base64;
import com.testcase.www.itpserver.wsdl.ArrayOfDoc;
import com.testcase.www.itpserver.wsdl.ArrayOfKeyValue;
import com.testcase.www.itpserver.wsdl.ArrayOfString;
import com.testcase.www.itpserver.wsdl.Doc;
import com.testcase.www.itpserver.wsdl.KeyValue;
public class testClient {
private static String endPoint = "http://pcwin7:8080/?WSDL";
// private static String endPoint = "http://pcwin7:8082/";
public static void main(String[] args) {
try {
Service service = new Service();
service.setTypeMappingVersion("1.2");
OperationDesc oper = new
org.apache.axis.description.OperationDesc();
oper.setName("SubmitEx");
ParameterDesc param = new
org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("
http://www.testcase.com/itpserver/wsdl", "service"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"),
java.lang.String.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("
http://www.testcase.com/itpserver/wsdl", "parms"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.testcase.com/itpserver/wsdl",
"ArrayOfString"), com.testcase.www.itpserver.wsdl.ArrayOfString.class,
false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("
http://www.testcase.com/itpserver/wsdl", "inKeyValues"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.testcase.com/itpserver/wsdl",
"ArrayOfKeyValue"), com.testcase.www.itpserver.wsdl.ArrayOfKeyValue.class,
false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("
http://www.testcase.com/itpserver/wsdl", "inDocuments"),
org.apache.axis.description.ParameterDesc.IN, new
javax.xml.namespace.QName("http://www.testcase.com/itpserver/wsdl",
"ArrayOfDoc"), com.testcase.www.itpserver.wsdl.ArrayOfDoc.class, false,
false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("
http://www.testcase.com/itpserver/wsdl", "error"),
org.apache.axis.description.ParameterDesc.OUT, new
javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"),
java.lang.String.class, false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("
http://www.testcase.com/itpserver/wsdl", "outKeyValues"),
org.apache.axis.description.ParameterDesc.OUT, new
javax.xml.namespace.QName("http://www.testcase.com/itpserver/wsdl",
"ArrayOfKeyValue"), com.testcase.www.itpserver.wsdl.ArrayOfKeyValue.class,
false, false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("
http://www.testcase.com/itpserver/wsdl", "outDocuments"),
org.apache.axis.description.ParameterDesc.OUT, new
javax.xml.namespace.QName("http://www.testcase.com/itpserver/wsdl",
"ArrayOfDoc"), com.testcase.www.itpserver.wsdl.ArrayOfDoc.class, false,
false);
oper.addParameter(param);
param = new
org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("
http://www.testcase.com/itpserver/wsdl", "progress"),
org.apache.axis.description.ParameterDesc.OUT, new
javax.xml.namespace.QName("http://www.testcase.com/itpserver/wsdl",
"ArrayOfString"), com.testcase.www.itpserver.wsdl.ArrayOfString.class,
false, false);
oper.addParameter(param);
oper.setReturnType(org.apache.axis.encoding.XMLType.AXIS_VOID);
oper.setStyle(org.apache.axis.constants.Style.DOCUMENT);
oper.setUse(org.apache.axis.constants.Use.LITERAL);
Call call = (Call)service.createCall();
call.setOperation(oper);
call.setTargetEndpointAddress( new
java.net.URL(endPoint) );
call.setUseSOAPAction(true);
call.setSOAPActionURI("
http://www.testcase.com/itpserver/wsdl/SubmitEx");
call.setEncodingStyle(null);
call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR,
Boolean.FALSE);
call.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS,
Boolean.FALSE);
call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
call.setOperationName(new javax.xml.namespace.QName("",
"SubmitEx"));
String theService = "CreateDocument";
ArrayOfString parms = new ArrayOfString(); // not
used
ArrayOfKeyValue inKeyValues = new
ArrayOfKeyValue();
inKeyValues.setKeyValue(new KeyValue[]{new
KeyValue("Email", "rude@sofico.be")}) ;
ArrayOfDoc inDocuments = new ArrayOfDoc();
inDocuments.setDoc(new Doc[]{new Doc("Data", new
byte[0])});
String ret = (String) call.invoke( new
Object[]{theService, parms, inKeyValues, inDocuments} );
// 1.log response msg ==> this message shows that
there are 4 elements:
// error
// outKeyValues
// outDocuments
// progres
logResponseMsg(call.getResponseMessage());
// 2.when i print ALL the outputparams I only see
the first param.
// when looking in the code that fills the map i
see:
// call.invoke ==> soapenvelope.getfirstbody ==>
body.getfirstboy ==> getChildren().get(0)!!! (see SOAPBODY.getFirstBody)
// ==> only the first param is put in the
outputparam ... I expected it would contain the 4 elements that are
present in the response MSG
logOutputParams(call.getOutputParams());
// 3.when manually parsing it is possible to
retrieve/decode/store the document from the response msg
parseMsgManual(call.getResponseMessage());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void parseMsgManual(Message msg) throws AxisFault{
System.out.println("\n\n manual parsing of the received
params:");
Vector<Node> v = msg.getSOAPEnvelope().getBodyElements();
Iterator<Node> it2 = v.iterator();
while(it2.hasNext()){
Node cur= it2.next();
System.out.println(cur.getNodeName() );
if("outDocuments".equals(cur.getNodeName())){
Node n = cur.getFirstChild();
if(n != null){
String docName = null;
byte[] content = null;
NodeList docInfo =
n.getChildNodes();
Node docID = docInfo.item(0);
Node doc = docInfo.item(1);
if(docID != null)
docName =
docID.getFirstChild().getNodeValue();
if(doc != null){
String tmp =
doc.getFirstChild().getNodeValue();
content =
Base64.decodeBuffer(tmp);
}
if(docName != null && content !=
null){
writeBytes(content,
"c:/output.pdf");
}
}
}
}
}
private static void logOutputParams(Map output){
System.out.println("Printing of all received output
params");
Iterator it = output.keySet().iterator();
while(it.hasNext()){
Object key = it.next();
String val = (String)output.get(key);
System.out.println(key + " : " + val);
}
}
private static void logResponseMsg(Message msg) throws AxisFault,
Exception{
String s =
XMLUtils.DocumentToString(msg.getSOAPEnvelope().getAsDocument());
writeBytes(s.getBytes(), "c:/response.xml");
}
// this msg is not relevant to the issue, just required do write
the output in a file...
private static final int BUFFER = 1024;
private static boolean writeBytes(byte[] theBytes, String
filePath) {
boolean result = false;
FileOutputStream lRepOut = null;
try {
lRepOut = new FileOutputStream(filePath, false);
// Empty files are possible!
if(theBytes==null)
theBytes = new byte[0];
int length = theBytes.length;
for (int i = 0; i < length; i += BUFFER) {
int chunk = BUFFER;
if(i+BUFFER > length){ // avoid index out
of bounds when writing last part of file
chunk = length - i;
}
lRepOut.write(theBytes, i, chunk);
}
result = true;
} catch (java.io.IOException ex) {
System.out.println("Failed to write to file '" +
filePath + "' :" + ex.getMessage());
if (lRepOut != null) {
try {
lRepOut.close();
} catch (Exception ignoreClosingExc) {
}
}
// throw the error so the user is informed.
ex.printStackTrace();
} finally {
try {
if (lRepOut != null) {
lRepOut.flush();
lRepOut.close();
}
} catch (IOException e) {
}
}
return result;
}
}
Any feedback is appreciated!