I have searched the archives, but have not gotten quite enough of a clue to solve the problem I face. I wish to use Java to get the results from a call to a SOAP server running Perl SOAP::Lite. The function returns a hash ref, encoded as SOAP::Lite encodes. (raw soap call/return below.)
I apologize for the long message, but I have found that God is in the details in this space, and if it is just a simple typo in some routine, the real source is required.
The server is running SOAP::Lite 0.55. It is sending back a hashref, and I have not been able to create the proper WSDL to see it, possibly because of how SOAP::Lite is sending back that hashref. I can handle simple types like ints and strings, but this is not working.
I am using stubs created by wsdl2java, so clearly I need to express this soap-struct in my WSDL, but I do not seem to be able to create the proper type in the WSDL, or at least, it is not being used.
I cannot really change the underlying routines on the server, as they are used for many things, but I can modify the dispatch function called by mod_perl. I have attached it at the end.
The request:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
URL: http://feature.alodar.com/gbib-soap/
-->
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
soap:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<s0:get_user_ids_by_name xmlns:s0="http://feature.alodar.com/Alodar/GBIB/UserUtils">
<s0:arg1Name>config_name</s0:arg1Name>
<s0:arg1Value>feature</s0:arg1Value>
</s0:get_user_ids_by_name>
</soap:Body>
</soap:Envelope>
The response:
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:namesp2="http://xml.apache.org/xml-soap" soap-env:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/">
<soap-env:body>
<namesp1:get_user_ids_by_nameresponse xmlns:namesp1="http://feature.alodar.com/Alodar/GBIB/UserUtils">
<s-gensym3 xsi:type="namesp2:SOAPStruct">
<admin xsi:type="xsd:int">
1
</admin>
<guest xsi:type="xsd:int">
2
</guest>
</s-gensym3>
</namesp1:get_user_ids_by_nameresponse>
</soap-env:body>
</soap-env:envelope>
my WSDL:
<?xml version="1.0" encoding="utf-8"?> <definitions name="GBIB" targetNamespace="http://feature.alodar.com/Alodar/GBIB/" xmlns:schema="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://feature.alodar.com/Alodar/GBIB/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xml-soap="http://xml.apache.org/xml-soap" xmlns="http://schemas.xmlsoap.org/wsdl/" >
<types>
<!-- I could use the following by defining the type returned from a
part of a message as
<message name="ListOfUsers">
<part name="models" type="tns:Vector">
</message>
<xsd:schema
targetNamespace="http://feature.alodar.com/Alodar/GBIB/"
xmlns="http://www.w3.org/2001/XMLSchema/">
<schema:complexType name="Vector">
<xsd:element name="elementData" type="schema:String" />
<xsd:element name="elementCount" type="schema:int" />
</schema:complexType>
</xsd:schema>
-->
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://feature.alodar.com/Alodar/GBIB/"
>
<complexType name="idNameMap">
<element name="elementData" type="string" />
<element name="elementCount" type="int" />
</complexType>
<complexType name="SOAPStruct">
<all>
<element name="varString" type="string"/>
<element name="varInt" type="int"/>
</all>
</complexType>
</schema>
</types>
<message name="config_nameRequest">
<part name="arg1Name" type="schema:string" />
<part name="arg1Value" type="schema:string" />
</message>
<message name="stringStringRequest">
<part name="arg1Name" type="schema:string" />
<part name="arg1Value" type="schema:string" />
<part name="arg2Name" type="schema:string" />
<part name="arg2Value" type="schema:string" />
</message>
<message name="stringIntRequest">
<part name="arg1Name" type="schema:string" />
<part name="arg1Value" type="schema:string" />
<part name="arg2Name" type="schema:string" />
<part name="arg2Value" type="schema:int" />
</message>
<message name="idNameMapResponse">
<!-- part name="idNameMapReturnValue" type="xml-soap:Map" / -->
<part name="idNameMapReturnValue" type="tns:idNameMap" />
</message>
<message name="stringResponse">
<part name="stringReturnValue" type="schema:string" />
</message>
<message name="intResponse">
<part name="stringReturnValue" type="schema:int" />
</message>
<message name="get_public_listsResponse">
<part name="get_public_listsReturnValue" type="schema:anyType" />
</message>
<portType name="UserUtilsPort">
<!-- ports are analogous to method calls. SR says analogous to library/module/class -->
<!-- name must match some binding's type -->
<operation name="get_user_ids_by_name">
<input message="tns:config_nameRequest" />
<output message="tns:idNameMapResponse" />
</operation>
<operation name="get_id_for_username">
<input message="tns:stringStringRequest" />
<output message="tns:intResponse" />
</operation>
<operation name="get_username_for_id">
<input message="tns:stringIntRequest" />
<output message="tns:stringResponse" />
</operation>
</portType>
<portType name="ListUtilsPort">
<!-- ports are analogous to method calls. -->
<!-- name must match some binding's type -->
<operation name="get_public_lists">
<input message="tns:config_nameRequest" />
<output message="tns:stringResponse" />
</operation>
</portType>
<binding name="UserUtils" type="tns:UserUtilsPort">
<!-- binding elements tell code how to move data. We are using SOAP -->
<!-- These are analagous to classes -->
<!-- type matches name of some port -->
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="get_id_for_username">
<soap:operation style="rpc" />
<input>
<soap:body use="encoded" namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</input>
<output>
<soap:body use="encoded" namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
</operation>
<operation name="get_user_ids_by_name">
<soap:operation style="rpc" />
<input>
<soap:body use="encoded" namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</input>
<output>
<soap:body use="encoded" namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
</operation>
<operation name="get_username_for_id">
<soap:operation style="rpc" />
<input>
<soap:body use="encoded" namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</input>
<output>
<soap:body use="encoded" namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
</operation>
</binding>
<binding name="ListUtils" type="tns:ListUtilsPort">
<!-- binding elements tell code how to move data. We are using SOAP -->
<!-- These are analagous to classes -->
<!-- type matches name of some port -->
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="get_public_lists">
<soap:operation style="rpc" />
<input>
<soap:body use="encoded" namespace="http://feature.alodar.com/Alodar/GBIB/ListUtils" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</input>
<output>
<soap:body use="encoded" namespace="http://feature.alodar.com/Alodar/GBIB/ListUtils" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
</operation>
</binding>
<service name="GBIBService">
<!-- service tells us what bindings to use. These give actual machines that implement the protocol. -->
<!-- document>
For a complete description of this service, go to the following URL:
<a href="http://feature.alodar.com/">
http://feature.alodar.com/
</a>
</document -->
<port name="UserUtils" binding="tns:UserUtils">
<soap:address location="http://feature.alodar.com/gbib-soap" />
</port>
<port name="ListUtils" binding="tns:ListUtils">
<soap:address location="http://feature.alodar.com/gbib-soap" />
</port>
</service>
</definitions>
The java code:
public void callFeatureStub() {
try{
String endpoint = "http://feature.alodar.com/gbib-soap/";UserUtilsPort userUtilsPort = new GBIBServiceLocator().getUserUtils(new URL(endpoint));
((UserUtilsStub)userUtilsPort).setTimeout(60000);
ListUtilsPort listUtilsPort = new GBIBServiceLocator().getListUtils(new URL(endpoint));
((ListUtilsStub)listUtilsPort).setTimeout(60000);
// works great!
int get_id_for_usernameResult=userUtilsPort.get_id_for_username("config_name ", config_name, "username", "admin");
printResult("get_id_for_username", get_id_for_usernameResult);
//works great!
String get_username_for_idResult=userUtilsPort.get_username_for_id("config_name ", config_name, "user_id", 1);
printResult("get_username_for_id", get_username_for_idResult);
// throws exception
Object get_user_ids_by_nameResult = userUtilsPort.get_user_ids_by_name("config_name", config_name);
printResult("get_user_ids_by_name", get_user_ids_by_nameResult);
} catch (Exception e) {
System.err.println("Error: "+e.toString());
}
}The dispatcher is very simple:
sub handler {
SOAP::Transport::HTTP::Apache -> dispatch_to(
qw(
Alodar::GBIB::ListUtils::get_public_lists
Alodar::GBIB::UserUtils::get_id_for_username
Alodar::GBIB::UserUtils::get_user_ids_by_name
Alodar::GBIB::UserUtils::get_username_for_id
)
) ->handler(@_)I can add more things to this, as long as they can go here.
The exception is:
[java] Result of get_id_for_username was type int, value 1
[java] Result of get_username_for_id was type java.lang.String, value admin
[java] - Exception:
[java] org.xml.sax.SAXException: Deserializing parameter 's-gensym39': could not find deserializer for type {http://xml.apache.org/xml-soap}SOAPStruct
[java] at org.apache.axis.message.RPCHandler.onStartChild(RPCHandler.java:302)
[java] Error: org.xml.sax.SAXException: Deserializing parameter 's-gensym39': could not find deserializer for type {http://xml.apache.org/xml-soap}SOAPStruct
[java] at org.apache.axis.encoding.DeserializationContextImpl.startElement(Deseria lizationContextImpl.java:963)
[java] at org.apache.axis.message.SAX2EventRecorder.replay(SAX2EventRecorder.java: 198)
[java] at org.apache.axis.message.MessageElement.publishToHandler(MessageElement.j ava:722)
[java] at org.apache.axis.message.RPCElement.deserialize(RPCElement.java:233)
[java] at org.apache.axis.message.RPCElement.getParams(RPCElement.java:347)
[java] at org.apache.axis.client.Call.invoke(Call.java:2272)
[java] at org.apache.axis.client.Call.invoke(Call.java:2171)
[java] at org.apache.axis.client.Call.invoke(Call.java:1691)
[java] at com.alodar.feature.Alodar.GBIB.UserUtilsStub.get_user_ids_by_name(UserUt ilsStub.java:187)
[java] at axisTest.callFeatureStub(axisTest.java:71)
[java] at axisTest.main(axisTest.java:46)
Scott
