SOAP client example in RDML

There is a nice sample in the LANSA Integrator Guide but as with many of the examples the information about how to understand how something else could be done is more difficult to find.

So I spent some time trying to create a simple SOAP client. But, unlike the example in the guide, this one would be without fragments – a single root element with a number of elements directly within. Specifically, the GetCityWeatherByZIP public sample, as I was just trying the SOAP services out.

I followed the instructions in the guide to create an Integrator solution, map the parameters, build and deploy, but coming up to the actual program I had trouble getting the data from the SOAP response. The field were not being bound to the response.

It turned out to quite simple

My experiment is written in RDML as I thought it would be best to get in running on the least-capable platform first. In RDMLX you can have more than one connection at the same time, using different JSMX handles, but I did not need that here.

Function Options(*DIRECT)
* The following fields should be defined in the dictionary
Define Field(#JSMSTS) Type(*CHAR) Length(20)
Define Field(#JSMMSG) Type(*CHAR) Length(256)
Define Field(#JSMCMD) Type(*CHAR) Length(256)
* The following fields are used by the soap binding map
Define Field(#RESULT) Type(*CHAR) Length(256) Label('Reply:')
Define Field(#DEBUG) Reffld(#RESULT) Label('Debug:')
* The following fields are used by the soap binding map
Define Field(#ZIP) Type(*CHAR) Length(5) Label('Zip..:')
Define Field(#CITY) Type(*CHAR) Length(20)
Define Field(#DESC) Type(*CHAR) Length(20)
Define Field(#PRES) Type(*CHAR) Length(20)
Define Field(#RELHUM) Type(*CHAR) Length(20)
Define Field(#REMARKS) Type(*CHAR) Length(20)
Define Field(#RESPONSE) Type(*CHAR) Length(20)
Define Field(#STATE) Type(*CHAR) Length(20)
Define Field(#SUCCESS) Type(*CHAR) Length(20)
Define Field(#TEMP) Type(*CHAR) Length(20)
Define Field(#VISI) Type(*CHAR) Length(20)
Define Field(#WIND) Type(*CHAR) Length(20)
Define Field(#WINDCHILL) Type(*CHAR) Length(20)
Def_List Name(#SOAPLIST) Fields(#CITY #DESC #PRES #RELHUM #REMARKS #RESPONSE #STATE #SUCCESS #TEMP #VISI #WIND #WINDCHILL) Type(*WORKING)
Change Field(#ZIP) To('''80210''') /* Denver */
Dowhile Cond('A *EQ A')
Request Fields((#FUNCTION *L1 *P2 *OUT) (#DATE *L1 *P73 *OUT) (#ZIP *L4 *P2 *LAB) (#DEBUG *L7 *P2 *LAB *OUT)) Design(*ACROSS) Identify(*NOID) Down_Sep(1) Across_Sep(1) Exit_Key(*YES *NEXT) Menu_Key(*NO) Text((*TMAP002 1 1)) Std_Head(*NO)
* F-keys
Case Of_Field(#IO$KEY)
When Value_Is('*EQ ''03''')
Return
Endcase
Change Field(#DEBUG) To(*BLANKS)
* Open service
Use Builtin(JSM_OPEN) To_Get(#JSMSTS #JSMMSG)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
* Load service
Change Field(#JSMCMD) To('SERVICE_LOAD SERVICE(SOAPAgentService) TRACE(*YES)')
Use Builtin(JSM_COMMAND) With_Args(#JSMCMD) To_Get(#JSMSTS #JSMMSG)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
* Open SOAP service
Change Field(#JSMCMD) To('OPEN SERVICE(WEATHER2)')
Use Builtin(JSM_COMMAND) With_Args(#JSMCMD) To_Get(#JSMSTS #JSMMSG)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
* Set operation - GETCITYWEATHERBYZIP
Change Field(#JSMCMD) To('SET OPERATION(GETCITYWEATHERBYZIP)')
Use Builtin(JSM_COMMAND) With_Args(#JSMCMD) To_Get(#JSMSTS #JSMMSG)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
* Set parameter - ZIP
Change Field(#JSMCMD) To('SET PARAMETER(ZIP) SERVICE_EXCHANGE(*FIELD)')
Use Builtin(JSM_COMMAND) With_Args(#JSMCMD) To_Get(#JSMSTS #JSMMSG)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
* Call remote service
Change Field(#JSMCMD) To('CALL SERVICE_LIST(CITY,DESC,PRES,RELHUM,REMARKS,RESPONSE,STATE,SUCCESS,TEMP,VISI,WIND,WINDCHILL)')
Use Builtin(JSM_COMMAND) With_Args(#JSMCMD) To_Get(#JSMSTS #JSMMSG #SOAPLIST)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
Change Field(#JSMCMD) To('IS NOT_NULL(*RETURN)')
Use Builtin(JSM_COMMAND) With_Args(#JSMCMD) To_Get(#JSMSTS #JSMMSG)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
* Close SOAP service
Use Builtin(JSM_COMMAND) With_Args('CLOSE') To_Get(#JSMSTS #JSMMSG)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
* Unload service
Use Builtin(JSM_COMMAND) With_Args('SERVICE_UNLOAD') To_Get(#JSMSTS #JSMMSG)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
* Close service
Use Builtin(JSM_CLOSE) To_Get(#JSMSTS #JSMMSG)
Execute Subroutine(CHECK) With_Parms(#JSMSTS #JSMMSG)
Display Fields(#CITY #DESC #PRES #RELHUM #REMARKS #RESPONSE #STATE #SUCCESS #TEMP #VISI #WIND #WINDCHILL)
Endwhile
* Check routine
Subroutine Name(CHECK) Parms((#JSMSTS *RECEIVED) (#JSMMSG *RECEIVED))
If Cond('#JSMSTS *NE OK')
Use Builtin(JSM_CLOSE) To_Get(#JSMSTS #JSMMSG)
Use Builtin(BCONCAT) With_Args(#DEBUG 'error') To_Get(#DEBUG)
Endif
Endroutine

The tiny change that made this work was changing

Change Field(#JSMCMD) To('CALL')

to

Change Field(#JSMCMD) To('CALL SERVICE_LIST(CITY,DESC,PRES,RELHUM,REMARKS,RESPONSE,STATE,SUCCESS,TEMP,VISI,WIND,WINDCHILL)')

which is the list of all the fields I had defined in the Integrator setup. It did not work when I was testing it with just a couple of the fields.

If the response is best split in fragments, I expect the code in the guide to be usable.

Other resources:

http://www.lansa.com/resources/implementing-soap-web-services-with-lansa-integrator.htm

http://www.lansa.com/support/tips/soaptutorials.htm

http://www.lansa.com/support/tips/t0382.htm