Calling a Web service roughly requires the following:
- An operation name.
- The arguments of that operation.
- A WSDL document that describes how to turn the operation
and its arguments into a (SOAP) request.
Tools such as Axis offer means to convert the WSDL document into Java classes, so calling an operation is just calling a specific method, and providing arguments is simply instantiating the appropriate Java classes.
The drawbacks are:
- Static generation of Java classes is needed for each new Web service.
- Calling those classes from an application that provide a generic
interface to any Web service is cumbersome. It almost requires to redo
the same job as WSDL2Java, but for building "scenarios" that explain how
to instantiate the classes in question, using reflection.
The application we are trying to develop is a kind of generic operation caller that takes as input (to keep it simple) a Web service address, an operation name, and operation arguments as XML chunks. We assume that the latter are compliant with the XSD contained in the WSDL document associated with the Web service. Likewise, the response is also XML chunks derived one way or the other from the SOAP response.
The problem is that those XML chunks are not exactly the ones inserted in the final SOAP request. And the question is: any suggestions how to build the final SOAP request from those chunks without (1) Java code generation, (2) dealing with low level SOAP stuff? In other words, is it possible to leverage what is already done for that matter in Axis, for example?
If the question is clear enough, you may skip the following.
------------------------------------------------------------
Example (taken from the "echo" sample provided by Axis):
- Operation name: echoNestedArray
- One argument whose description is given by this XSD:
<complexType name="SOAPArrayStruct">
<sequence>
<element name="varString" nillable="true" type="xsd:string" />
<element name="varInt" type="xsd:int" />
<element name="varFloat" type="xsd:float" />
<element name="varArray" nillable="true" type="tns1:ArrayOfstring" />
</sequence>
</complexType>
<element name="SOAPArrayStruct" nillable="true" type="tns1:SOAPArrayStruct" />
This is an example of input XML chunk given to the generic application mentioned above. Note that the names of the elements are compliant with the XSD, but nothing is specified about the types.
<SOAPArrayStruct>
<varInt>1</varInt>
<varFloat>3.0</varFloat>
<varArray>
<item>one</item>
<item>two</item>
<item>three</item>
</varArray>
<varString>AXIS</varString>
</SOAPArrayStruct>
And this is the final SOAP request (the envelope is not shown here) that will evetually be sent:
<ns1:echoNestedArray xmlns:ns1="http://soapinterop.org/">
<inputStruct href=""#id0"/>
</ns1:echoNestedArray>
<multiRef id="id0" SOAP-ENC:root="0" xsi:type="ns2:SOAPArrayStruct" xmlns:ns2="http://soapinterop.org/xsd">
<varFloat xsi:type="xsd:float">3.0</varFloat>
<varInt xsi:type="xsd:int">1</varInt>
<varArray xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="xsd:string[3]">
<item xsi:type="xsd:string">one</item>
<item xsi:type="xsd:string">two</item>
<item xsi:type="xsd:string">three</item>
</varArray>
<varString xsi:type="xsd:string">AXIS</varString>
</multiRef>
Given the WSDL document, the operation name, and that XML chunk, is there any existing tool that allow dynamically building the final SOAP request?
We tried to use Axis serializer/deserializer factories in order to achieve that, but there was a snag: it is not possible to use the same serializer/deserializer corresponding to a generic Java class and associated with different elements. For example, consider that we have a class "GenericStruct" that holds any kind of XML chunk (the class could as well be org.w3c.dom.Element, the idea is the same); also consider the class "GenericSerializer" that serializes instances of "GenericStruct" (could also be org.apache.axis.encoding.ser.ElementSerializer). The problem is that GenericStruct.class will be associated with the SOAPArrayStruct QName and *only* with that QName. If there is another element called "SOAPOtherStruct" that we try to pair with GenericStruct.class, there will be a clash. Axis expects a different Java class for each type defined in the WSDL document, which leads back to the Java code generation problem that we are trying to avoid.
It probably is doable by using low-level interfaces and deal directly with classes such as org.apache.axis.message.RPCElement or org.apache.axis.message.SOAPBodyElement, but any suggestion to avoid going deep down there is welcome.
Cheers,
Jean-Claude
