I've been using the Thomas Raddatz WSDL2RPG tool, but I'm seeing some occurrences of failures. Getting the error "-1: Length of varying length variable is out of range." If I recall correctly, this error may have originated in one of the WSDL2R94 procedures. After a lot of digging around, I find that on these occurrences, there appears to be a couple of different data maps being returned by the webservice. The production program is handling the simple type, where I receive back items defined as: D impl_getRGDeviceDetailsReturnMvd_t... D DS template D qualified D item likeds(apachesoap_RpgArrayOfItem_t) D apachesoap_RpgArrayOfItem_t... D DS template D qualified D x 10I 0 D mapItem likeds(apachesoap_mapItem_t) D dim(DIM_A1) // DIM_A1 = 512 D apachesoap_mapItem_t... D DS template D qualified D key 256A varying D value 256A varying This works well until I encounter a nested array, where the "Value" is actually a map of a number of key/value pairs. So I messed with it until I got a test program to accommodate those. (I used patterns from another program Thomas helped me set up last August.) I also had to do a lot of trial/error to get the array dimensions right so it would compile and run without error. It now runs without error (at least for my very limited test inputs), and I can get the key/value pairs of the inner nested values, using the following definitions in my test stubs: D apachesoap_RpgArrayOfItem_t... D DS template D qualified D x 10I 0 D mapItem likeds(apachesoap_mapItem_t) D dim(DIM_A1) // DIM_A1 = 400 for this test stub D apachesoap_mapItem_t... D DS template D qualified D key 64A varying D value likeds(apachesoap_AnyMap_t) D apachesoap_AnyMap_t... D DS template D qualified D item likeds(apachesoap_RpgArrayOfItem1_t) D apachesoap_RpgArrayOfItem1_t... D DS template D qualified D x 10I 0 D anyMapItem likeds(apachesoap_anyMapItem_t) D dim(DIM_A2) // DIM_A2 = 64 for this test stub D apachesoap_anyMapItem_t... D DS template D qualified D key 64A varying D value 64A varying All is cool except that the returned data is a mix of the nested types and the simple types. I have not found a way to resolve the simple value, which my test stubs don't appear to resolve. I get the "simple" key, but the value is expected to also be a nested set of key/value pairs, which for some pairs it is, but others it is not. I know what the result set should be from a "northbound Interface" that should be using the same web service, and I see the different types of data maps there. I just can't seem to replicate those results with my programs. Attached is the original wsdl from the web service (Provision.wsdl) and a modified version that provides for the nested key/value pairs (Provision4.wsdl). The method I'm working with here is getRGDeviceDetails. I've attached my test caller as well (ws5test05.txt). If you think you can help me through this, let me know what other pieces you might need. Many thanks, Michael
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="urn:Provision" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="urn:Provision" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:intf="urn:Provision"> <!--WSDL created by Apache Axis version: 1.4 Built on Apr 22, 2006 (06:55:48 PDT)--> <wsdl:types> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xml.apache.org/xml-soap"> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="mapItem"> <sequence> <element name="key" nillable="true" type="xsd:anyType"/> <element name="value" nillable="true" type="xsd:anyType"/> </sequence> </complexType> <complexType name="Map"> <sequence> <element name="item" minOccurs="0" maxOccurs="unbounded" type="apachesoap:mapItem"/> </sequence> </complexType> </schema> </wsdl:types> <wsdl:message name="deprovisionPortRequest"> <wsdl:part name="in0" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="sendDeviceCommandResponse"> <wsdl:part name="sendDeviceCommandReturn" type="soapenc:string"/> </wsdl:message> <wsdl:message name="backupDeviceConfigRequest"> <wsdl:part name="in0" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="modifyPortResponse"> <wsdl:part name="modifyPortReturn" type="soapenc:string"/> </wsdl:message> <wsdl:message name="getRGDeviceDetailsResponse"> <wsdl:part name="getRGDeviceDetailsReturn" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="getDeviceInterfacesRequest"> <wsdl:part name="in0" type="soapenc:string"/> <wsdl:part name="in1" type="soapenc:string"/> </wsdl:message> <wsdl:message name="provisionPortResponse"> <wsdl:part name="provisionPortReturn" type="soapenc:string"/> </wsdl:message> <wsdl:message name="modifyRGRequest"> <wsdl:part name="in0" type="apachesoap:Map"/> <wsdl:part name="in1" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="deprovisionPortResponse"> <wsdl:part name="deprovisionPortReturn" type="soapenc:string"/> </wsdl:message> <wsdl:message name="getDeviceVlansRequest"> <wsdl:part name="in0" type="soapenc:string"/> <wsdl:part name="in1" type="soapenc:string"/> </wsdl:message> <wsdl:message name="getRGDeviceDetailsRequest"> <wsdl:part name="in0" type="apachesoap:Map"/> <wsdl:part name="in1" type="soapenc:string"/> </wsdl:message> <wsdl:message name="getDeviceVlansResponse"> <wsdl:part name="getDeviceVlansReturn" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="sendDeviceCommandRequest"> <wsdl:part name="in0" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="modifyPortRequest"> <wsdl:part name="in0" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="provisionPortRequest"> <wsdl:part name="in0" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="backupDeviceConfigResponse"> <wsdl:part name="backupDeviceConfigReturn" type="soapenc:string"/> </wsdl:message> <wsdl:message name="getDeviceInterfacesResponse"> <wsdl:part name="getDeviceInterfacesReturn" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="modifyRGResponse"> <wsdl:part name="modifyRGReturn" type="soapenc:string"/> </wsdl:message> <wsdl:portType name="ProvisionInterface"> <wsdl:operation name="getDeviceInterfaces" parameterOrder="in0 in1"> <wsdl:input name="getDeviceInterfacesRequest" message="impl:getDeviceInterfacesRequest"/> <wsdl:output name="getDeviceInterfacesResponse" message="impl:getDeviceInterfacesResponse"/> </wsdl:operation> <wsdl:operation name="getDeviceVlans" parameterOrder="in0 in1"> <wsdl:input name="getDeviceVlansRequest" message="impl:getDeviceVlansRequest"/> <wsdl:output name="getDeviceVlansResponse" message="impl:getDeviceVlansResponse"/> </wsdl:operation> <wsdl:operation name="getRGDeviceDetails" parameterOrder="in0 in1"> <wsdl:input name="getRGDeviceDetailsRequest" message="impl:getRGDeviceDetailsRequest"/> <wsdl:output name="getRGDeviceDetailsResponse" message="impl:getRGDeviceDetailsResponse"/> </wsdl:operation> <wsdl:operation name="provisionPort" parameterOrder="in0"> <wsdl:input name="provisionPortRequest" message="impl:provisionPortRequest"/> <wsdl:output name="provisionPortResponse" message="impl:provisionPortResponse"/> </wsdl:operation> <wsdl:operation name="deprovisionPort" parameterOrder="in0"> <wsdl:input name="deprovisionPortRequest" message="impl:deprovisionPortRequest"/> <wsdl:output name="deprovisionPortResponse" message="impl:deprovisionPortResponse"/> </wsdl:operation> <wsdl:operation name="modifyPort" parameterOrder="in0"> <wsdl:input name="modifyPortRequest" message="impl:modifyPortRequest"/> <wsdl:output name="modifyPortResponse" message="impl:modifyPortResponse"/> </wsdl:operation> <wsdl:operation name="modifyRG" parameterOrder="in0 in1"> <wsdl:input name="modifyRGRequest" message="impl:modifyRGRequest"/> <wsdl:output name="modifyRGResponse" message="impl:modifyRGResponse"/> </wsdl:operation> <wsdl:operation name="backupDeviceConfig" parameterOrder="in0"> <wsdl:input name="backupDeviceConfigRequest" message="impl:backupDeviceConfigRequest"/> <wsdl:output name="backupDeviceConfigResponse" message="impl:backupDeviceConfigResponse"/> </wsdl:operation> <wsdl:operation name="sendDeviceCommand" parameterOrder="in0"> <wsdl:input name="sendDeviceCommandRequest" message="impl:sendDeviceCommandRequest"/> <wsdl:output name="sendDeviceCommandResponse" message="impl:sendDeviceCommandResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="ProvisionSoapBinding" type="impl:ProvisionInterface"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getDeviceInterfaces"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getDeviceInterfacesRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:input> <wsdl:output name="getDeviceInterfacesResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="getDeviceVlans"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getDeviceVlansRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:input> <wsdl:output name="getDeviceVlansResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="getRGDeviceDetails"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getRGDeviceDetailsRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:input> <wsdl:output name="getRGDeviceDetailsResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="provisionPort"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="provisionPortRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:input> <wsdl:output name="provisionPortResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="deprovisionPort"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="deprovisionPortRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:input> <wsdl:output name="deprovisionPortResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="modifyPort"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="modifyPortRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:input> <wsdl:output name="modifyPortResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="modifyRG"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="modifyRGRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:input> <wsdl:output name="modifyRGResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="backupDeviceConfig"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="backupDeviceConfigRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:input> <wsdl:output name="backupDeviceConfigResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="sendDeviceCommand"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="sendDeviceCommandRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:input> <wsdl:output name="sendDeviceCommandResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:Provision"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="ProvisionService"> <wsdl:port name="Provision" binding="impl:ProvisionSoapBinding"> <wsdlsoap:address location="http://192.168.41.252:9090/axis/services/Provision"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
Attachment:
Provision4.wsdl
Description: Provision4.wsdl
* ===================================================================== * Generated by WSDL2RPG 1.15beta7 / 25.01.2012 * Built on Feb 14, 2013 (12:48:38) * Built for V7R1M0 * Based on WS_PGM v1.15 * ===================================================================== *CRTPGM PGM(gsttstlib/ws5test05) * MODULE(gsttstlib/ws5test05) * BNDSRVPGM(gsttstlib/ws5prvsn) *DETAIL(*BASIC) *ACTGRP(*NEW) *TEXT('Web service test caller - getRGDevDtls') * ===================================================================== * H DEBUG H OPTION(*SRCSTMT : *NODEBUGIO) H EXTBININT(*YES) * * Include generated web service stub module to * define the prototype of the web service procedure * and the required type definitions (aka reference fields). /DEFINE PROTOTYPE_WS5PRVSN05 CPY /COPY MKOESTER/WS_STUBSRC,WS5PRVSN05 /UNDEFINE PROTOTYPE_WS5PRVSN05 * * Program entry point D WS5TEST05... D PR * * Sends a message to the command line. D sndMsg... D PR extproc('sndMsg') D i_text 128A value varying * * ===================================================================== * Program entry point * ===================================================================== D WS5TEST05... D PI * * Web service error message text D errText S like(wsdl_errText_t ) inz * * Request message * These fields needs to be filled with reasonable values * right before calling the web service. D in0 DS likeds(apachesoap_AnyMap_t) D inz D in1 S like(impl_in1_t) D inz * * Response message * This structure contains the result values returned by * the web service. D getRGDeviceDetailsRpc... D DS likeds(impl_getRGDeviceDetailsRpc_t) D inz * * Text of messages sent to the command line D text S 128A varying inz D paircount1 s 5u 0 inz D paircount2 s 5u 0 inz D set# s 5u 0 inz D set2 s 5u 0 inz D DisplayThis S 52A varying inz D PairKey S 64a varying inz D PairValue S 64a varying inz D outerKey S 64a varying inz D outerValue S 64a varying inz D Fullstring S 150a 2/25 d NotNested dS qualified d key 64a varying d value 64a varying * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /free // Enable/disable http api debug log // (Enable the http api debug log in case of problems with the web service) test Provision_Port_setHttpDebug( test *ON: '/tmp/httpapi_debug.txt'); // Default path of http api // Specify a proxy server if your network requires it. // Provision_Port_setHttpProxy( // 'your.proxy.server': 8080); // Set the paramater values of the request message // of the web service. // assign values here // Set number of array items: in0.item.x = 1; // Set array item values: in0.item.anyMapItem(in0.item.x).key = 'upstreamDevicePort'; in0.item.anyMapItem(in0.item.x).value = '192.168.31.42_4.5'; in1 = ''; // Now let's call the web service. getRGDeviceDetailsRpc = Provision_getRGDeviceDetails( in0: in1: errText); // If the Web service finished successfully ... B01 if (not Provision_Port_isError()); // ... get response data from response data structure paircount1 = getRGDeviceDetailsRpc .getRGDeviceDetailsReturn .item .x; DSPLY ('item x is ' + %editc(paircount1 : '3') + '.'); if paircount1 > 0; for set# = 1 to paircount1; paircount2 = getRGDeviceDetailsRpc .getRGDeviceDetailsReturn .item .mapItem(set#) .value .item .x; if paircount2 > 0; DSPLY ('inner pairs: ' + %trim(%editc(paircount2 : '3')) + '.'); for set2 = 1 to paircount2; PairKey = getRGDeviceDetailsRpc .getRGDeviceDetailsReturn .item .mapItem(set#) .value .item .anyMapItem(set2) .key; PairValue = getRGDeviceDetailsRpc .getRGDeviceDetailsReturn .item .mapItem(set#) .value .item .anyMapItem(set2) .value; Fullstring = %trim(%editc(set# : '3')) + '/' + %trim(%editc(set2 : '3')) + ': ' + PairKey + ' => ' + PairValue; displayThis = %subst(Fullstring : 1 : 52); DSPLY (displayThis); endfor; else; 2/25 // Can we can get a view of the "simple" key/value pair 2/25 // by splitting them out in a data structure? 2/25 NotNested = getRGDeviceDetailsRpc 2/25 .getRGDeviceDetailsReturn 2/25 .item 2/25 .mapItem(set#); 2/25 outerKey = NotNested.Key; 2/25 outerValue = NotNested.Value; // outerKey = getRGDeviceDetailsRpc // .getRGDeviceDetailsReturn // .item // .mapItem(set#) // .key; // outerValue= getRGDeviceDetailsRpc // .getRGDeviceDetailsReturn // .item // .mapItem(set#) // .value 2/25 // .item 2/25 // .anyMapItem(1) 2/25 // .value; if outerKey <> *blanks or outerValue <> *blanks; Fullstring = %trim(%editc(set# : '3')) + ': ' + outerKey + ' => ' + outerValue; displayThis = %subst(Fullstring : 1 : 52); DSPLY (displayThis); endif; endif; endfor; endif; // exec sql // insert into RGDevDetls // (Order#, Phone#, PairKey, Pairvalue) // values (:Order#, :Phone#, :PairKey, :Pairvalue) // with nc; X01 else; // ... else show error messages ordered by priority: // 1. HTTP error information text = %char( Provision_HttpError_getCode() ) + ': ' + Provision_HttpError_getText() ; sndMsg(text); // 2. SOAP error information B02 if (Provision_SoapError_getCode() <> ''); text = Provision_SoapError_getCode() + ': ' + Provision_SoapError_getText() ; sndMsg(text); E02 endif; // 3. XML parser error information B02 if (Provision_XmlError_getCode() <> 0); text = %char(Provision_XmlError_getCode()) + ': ' + Provision_XmlError_getText() ; sndMsg(text); E02 endif; E01 endif; *inlr = *on; /end-free * * ===================================================================== * *** private *** * Sends a message to the command line. * ===================================================================== P sndMsg... P B * D sndMsg... D PI D i_text 128A value varying * * Local fields D msgKey S 4A inz * * Qualified message file name D qMsgF DS qualified inz D name 10A D lib 10A * * API error code D errCode DS qualified inz D bytPrv 10I 0 D bytAvl 10I 0 D excID 7A D reserved 1A D excDta 256A * * Send Program Message (QMHSNDPM) API D QMHSNDPM PR extpgm('QMHSNDPM') D i_msgID 7A const D i_qMsgF 20A const D i_msgData 32767A const options(*varsize ) D i_length 10I 0 const D i_msgType 10A const D i_callStkE 32767A const options(*varsize ) D i_callStkC 10I 0 const D o_msgKey 4A D io_ErrCode 32767A options(*varsize ) * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /free clear qMsgF; qMsgF.name = 'QCPFMSG'; qMsgF.lib = '*LIBL'; clear errCode; errCode.bytPrv = %size(errCode); QMHSNDPM('CPF9897': qMsgF: i_text: %len(i_text): '*INFO' : '*CTLBDY': 1: msgKey: errCode); return; /end-free * P sndMsg... P E *
----------------------------------------------------------------------- This is the FTPAPI mailing list. To unsubscribe, please go to: http://www.scottklement.com/mailman/listinfo/ftpapi -----------------------------------------------------------------------