Gents;
Now IceBreak supports Complex types for SOAP web services.
What is Complex types in SOAP?
Basically Complex types are data structures or "records". In IceBreak they are implemented as External data structures. So you can benefit from already described database files, which can be referred to directly. Complex types must always be described externally, to avoid overlays and overlaps, since SOAP needs "clean" structures for Complex types.
IceBreak automatically imports the external database description when the WSDL and the web service program is produced. Lets take a look at the following example:
A client want to request a list of rows from our product database table. In this example we use the same data structure for both input and output. In the "real world" you can use as many as you like and in combination with scalar fields.
Lets have a look at the program:
<%@ language="SQLRPGLE" pgmtype="webservice"%> <% h nomain debug d Product E DS based(prototype_only) qualified /* ----------------------------------------------------------------------------------- Get product descriptions for producst in the input list ----------------------------------------------------------------------------------- */ p getProduct... p b export d pi d inArr input likeds(Product) dim(10) d outArr output likeds(Product) dim(10) d rows 10i 0 output d* Internal work fields d i s 10i 0 d prodRec ds likeds(Product) /free // How many was sent to me in the input? rows = soap_ArrayElements(%addr(inarr)); for i = 1 to rows; // Get a row for each prodRec.prodKey = inArr(i).prodKey; exec sql select * into :prodRec from product where prodKey = :prodRec.prodKey; outArr(i) = prodRec; endFor; // This is how many we want to send back to the client soap_ArrayElements(%addr(outArr): rows); return; /end-free p e
As you can see; we are receiving a list of keys – the input of Complex type aka external structure is used as an array with the "dim". Now you need to check how many elements are actually provided by the client. This is done with the soap_ArrayElements() procedure in IceBreak.
Now you can safely iterate on each of the elements in the complex list, and like in this case use SQL to retrieve the complete record, which again are placed in our SOAP response.
Finally you need to tell how manu elements you have provided in the response, this, again is done with the soap_ArrayElements() procedure in IceBreak.
When you compile this, IceBreak will automatically create a WSDL file which will look like this – notice the complex type "product" in the following:
<?xml version="1.0" encoding="windows-1252"?> <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="<%$ uri %>/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="<%$ uri %>/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <wsdl:types> <s:schema elementFormDefault="qualified" targetNamespace="<%$ uri %>/"> <s:complexType name="product"> <s:sequence> <s:element name="prodkey" type="s:decimal"/> <s:element name="prodid" type="s:string"/> <s:element name="desc" type="s:string"/> <s:element name="manuid" type="s:string"/> <s:element name="price" type="s:decimal"/> <s:element name="stockcnt" type="s:decimal"/> <s:element name="stockdate" type="s:date"/> </s:sequence> </s:complexType> <s:element name="getProduct"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="10" name="inArr" type="tns:product" /> </s:sequence> </s:complexType> </s:element> <s:element name="getProductResponse"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="10" name="outArr" type="tns:product" /> <s:element minOccurs="0" maxOccurs="1" name="rows" type="s:decimal" /> </s:sequence> </s:complexType> </s:element> </s:schema> </wsdl:types> <wsdl:message name="getProductSoapIn"> <wsdl:part name="parameters" element="tns:getProduct" /> </wsdl:message> <wsdl:message name="getProductSoapOut"> <wsdl:part name="parameters" element="tns:getProductResponse" /> </wsdl:message> <wsdl:portType name="ServiceSoap"> <wsdl:operation name="getProduct"> <wsdl:input message="tns:getProductSoapIn"/> <wsdl:output message="tns:getProductSoapOut"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="ServiceSoap" type="tns:ServiceSoap"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="getProduct"> <soap:operation soapAction="<%$ uri %>/getProduct" style="document" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:binding name="ServiceSoap12" type="tns:ServiceSoap"> <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="getProduct"> <soap12:operation soapAction="<%$ uri %>/getProduct" style="document" /> <wsdl:input> <soap12:body use="literal" /> </wsdl:input> <wsdl:output> <soap12:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="wscomplex"> <wsdl:port name="ServiceSoap" binding="tns:ServiceSoap"> <soap:address location="<%$ uri %>/wscomplex.asmx" /> </wsdl:port> <wsdl:port name="ServiceSoap12" binding="tns:ServiceSoap12"> <soap12:address location="<%$ uri %>/wscomplex.asmx" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
Now Finally lets try the program;
From SoapUI, you can set up you request, with i.e. two keys, and have two resulting rows back (see attached screenshot)
Best regards,
Niels Liisberg
Re: IceBreak SOAP WebServices - Support for Complex Types
Thanks for the input!