Step 3 RDML Function Code

LANSA Integrator

Step 3: RDML Function Code

Following is the RDML code that can be used to process these orders. Please read the notes in the code carefully as they explain what is going on. There is also an RDMLX example in XMLBindFileService.

FUNCTION OPTIONS(*DIRECT)
 
* Define the fields to be used in this application
 
* Define the fields used by the JSM Commands
DEFINE FIELD(#JSMSTS) TYPE(*CHAR) LENGTH(020)
DEFINE FIELD(#JSMMSG) TYPE(*CHAR) LENGTH(255)
DEFINE FIELD(#JSMCMD) TYPE(*CHAR) LENGTH(255)
 
* Define the fields used for the orders.
* These fields will hold values read from and written to
* the XML documents
 
* Define the Order number and date
DEFINE FIELD(#SONUM) TYPE(*CHAR) LENGTH(010) LABEL('Order #')
DEFINE FIELD(#ORDDTE) TYPE(*CHAR) LENGTH(010) LABEL('Order Date')
 
* Define the Customer details
DEFINE FIELD(#CUSTNUM) TYPE(*CHAR) LENGTH(010) LABEL('Customer #')
DEFINE FIELD(#CUSTNME) TYPE(*CHAR) LENGTH(050) LABEL('Customer name')
DEFINE FIELD(#STREET) TYPE(*CHAR) LENGTH(050) LABEL('Street')
DEFINE FIELD(#CITY) TYPE(*CHAR) LENGTH(050) LABEL('City')
DEFINE FIELD(#STATE) TYPE(*CHAR) LENGTH(005) LABEL('State')
DEFINE FIELD(#ZIP) TYPE(*CHAR) LENGTH(005) LABEL('Post Code')
 
* Define the order line details. We will also define a
* list that holds the order line details
DEFINE FIELD(#LINENUM) TYPE(*DEC) LENGTH(003) DECIMALS(0) LABEL('Line #')
DEFINE FIELD(#PARTNUM) TYPE(*DEC) LENGTH(003) DECIMALS(0) LABEL('Part #')
DEFINE FIELD(#PARTDSC) TYPE(*CHAR) LENGTH(020) LABEL('Part Desc.')
DEFINE FIELD(#PARTAMT) TYPE(*DEC) LENGTH(010) DECIMALS(2) LABEL('Amount')
DEFINE FIELD(#PARTQTY) TYPE(*DEC) LENGTH(003) DECIMALS(0) LABEL('Quantity')
DEFINE FIELD(#ORDTOT) TYPE(*DEC) LENGTH(010) DECIMALS(2) LABEL('Grand Total')
DEF_LIST NAME(#ORDLINES) FIELDS(#LINENUM #PARTNUM #PARTDSC #PARTAMT #PARTQTY)
 
* The following field will hold the file name and path
* for the archived files
DEFINE FIELD(#ARCHIVE) TYPE(*CHAR) LENGTH(30) DESC('Archived Orders Directory') INPUT_ATR(LC) DEFAULT('''archive''')
DEFINE FIELD(#X_POSN) TYPE(*DEC) LENGTH(2) DECIMALS(0) DESC('Working field to find the file name')
 
* Define the order response details
DEFINE FIELD(#COMMENTS) TYPE(*CHAR) LENGTH(256) LABEL('Comments')
DEFINE FIELD(#LINSTAT) TYPE(*CHAR) LENGTH(20) LABEL('Line Status')
DEFINE FIELD(#RESPONSE) TYPE(*CHAR) LENGTH(30) LABEL('Resp filename')
DEFINE FIELD(#TOGGLE) TYPE(*DEC) LENGTH(1) DECIMALS(0)
DEF_LIST NAME(#LSTCMNT) FIELDS(#COMMENTS) TYPE(*WORKING)
DEF_LIST NAME(#RSPLINES) FIELDS(#LINENUM #PARTNUM #PARTDSC #PARTAMT #PARTQTY #LINSTAT) TYPE(*WORKING)
 
* A single field working list needs to be defined to
* hold the list of order returned from our LIST command.
* The field needs to be long enough to hold the expected
* length of the canonical file path returned from the
* LIST command.
DEFINE FIELD(#FILENAME) TYPE(*CHAR) LENGTH(100)
DEF_LIST NAME(#ORDERLSTW) FIELDS(#FILENAME) COUNTER(#LISTCOUNT) TYPE(*WORKING)
DEF_LIST NAME(#ORDERLSTB) FIELDS(#FILENAME) COUNTER(#LISTCOUNT)
 
* We will now start the funcionality by opening the JSM
USE BUILTIN(JSM_OPEN) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
* Next we will load the JSM service - in this example we
* have selected to have tracing on.
CHANGE FIELD(#JSMCMD) TO('SERVICE_LOAD SERVICE(XMLBINDFILESERVICE) TRACE(*YES) DOMSET(*READER)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
* The first thing we want to do is to get a list of all
* the orders that are in the neworders directory. To do
* this we will use the LIST command. In this scenario,
* the neworders directory is immediately under the JSM
* Instance directory on our server, so we can refer to
* the directory simply as 'neworders'.
* In this example the file extension has been hard coded
* as XML. This means that only files with an extension of
* XML will be returned.
CLR_LIST NAMED(#ORDERLSTW)
CHANGE FIELD(#JSMCMD) TO('''LIST DIR(NEWORDERS) SERVICE_LIST(FILENAME) EXT(XML)''')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG #ORDERLSTW)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
* Display the list returned from the LIST command.
CLR_LIST NAMED(#ORDERLSTB)
SELECTLIST NAMED(#ORDERLSTW)
ADD_ENTRY TO_LIST(#ORDERLSTB)
ENDSELECT
DISPLAY FIELDS(#JSMCMD) BROWSELIST(#ORDERLSTB) EXIT_KEY(*YES *NEXT) MENU_KEY(*YES *NEXT)
IF_KEY WAS(*MENU *EXIT)
* Nicely close down JSM if the user has select the Exit
* or Menu key (F3 or F12)
USE BUILTIN(JSM_CLOSE) TO_GET(#JSMSTS #JSMMSG)
ENDIF
 
* The next step of our application is to run through
* the orders in our list and process the data order by
* order. To do this we will need to use the READ, BIND,
* and GET commands.
 
SELECTLIST NAMED(#ORDERLSTW)
* Next we will use the READ command. For the READ
* command we need to specify the file that we want
* to access, including the file path. In this example,
* if an order is named order1.xml for example, then the
* FILE keyword would normally be specified as
* FILE(neworder/order1.xml), and it would assume that the
* neworder directory is under the JSM Instance directory
* for the server. We could take this approach, but we
* already have the full directory path and file name
* specified in the list (in the field #FILENAME) so it
* will be much simpler to use this. The actual ARCHIVE
* file name and path will be verified in the ARCHIVE
* sub-routine.
* If we were going to be using a hard coded READ, then
* this is what it might look like:
* .   USE BUILTIN(BUILTIN) WITH_ARGS(JSM_COMMAND)
* .   WITH_ARGS('READ FILE(neworder/order1.xml)
* .              ARCHIVE(archive/arc_order1.xml)')
* .   TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(ARCHIVE)
CHANGE FIELD(#JSMCMD) TO('READ FILE(')
USE BUILTIN(TCONCAT) WITH_ARGS(#JSMCMD #FILENAME ') ARCHIVE(' #ARCHIVE ')') TO_GET(#JSMCMD)
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
* The next command to run is the BIND. We named the
* service to handle the inbound XML documents as
* 'inboundorder'.
CHANGE FIELD(#JSMCMD) TO('''BIND SERVICE(INBOUNDORDER) TYPE(*INBOUND) BINDTRACE(*YES)''')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
* The next step is to retrieve the data using the GET
* command.
USE BUILTIN(JSM_COMMAND) WITH_ARGS('GET FRAGMENT(ORDERS) SERVICE_EXCHANGE(*FIELD)') TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
CHANGE FIELD(#JSMCMD) TO('GET FRAGMENT(SALESORDER) SERVICE_EXCHANGE(*FIELD)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
CHANGE FIELD(#JSMCMD) TO('GET FRAGMENT(CUSTOMER) SERVICE_EXCHANGE(*FIELD)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
CHANGE FIELD(#JSMCMD) TO('GET FRAGMENT(ORDERDATE) SERVICE_EXCHANGE(*FIELD)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
* The line details of our order technically make up a
* list. In this example though, we have defined the lines
* as fragments. As such, we need to handle them a little
* differently. We need to place the GET FRAGMENT(LINE) in
* a loop and continue in the loop until all the line
* details are retrieved. The following demonstrates how
* we do this.
CLR_LIST NAMED(#ORDLINES)
BEGIN_LOOP
USE BUILTIN(JSM_COMMAND) WITH_ARGS('GET FRAGMENT(LINE) SERVICE_EXCHANGE(*FIELD)') TO_GET(#JSMSTS #JSMMSG)
IF COND('#JSMSTS *EQ NOFRAGMENT')
LEAVE
ENDIF
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
* We also need to get the part details for this line.
USE BUILTIN(JSM_COMMAND) WITH_ARGS('GET FRAGMENT(PART) SERVICE_EXCHANGE(*FIELD)') TO_GET(#JSMSTS #JSMMSG)
 
ADD_ENTRY TO_LIST(#ORDLINES)
 

END_LOOP
 
* Now that we have everything for the order let us
* display it. In a real application of course you would
* carry on an load it into your ERP system or what have
* you, but we will just display it.
DISPLAY FIELDS(#SONUM #ORDDTE #CUSTNUM #CUSTNME #STREET #CITY #STATE #ZIP) BROWSELIST(#ORDLINES) EXIT_KEY(*YES *NEXT) MENU_KEY(*YES *NEXT)
IF_KEY WAS(*MENU *EXIT)
* Nicely close down JSM if the user has select the Exit
* or Menu key (F3 or F12)
USE BUILTIN(JSM_CLOSE) TO_GET(#JSMSTS #JSMMSG)
ENDIF
 
* Now that we have the data we need and have saved a copy
* of the file in the archive, we can close the bind on
* this file and delete the file from our inbound
* directory.
USE BUILTIN(JSM_COMMAND) WITH_ARGS(CLOSE) TO_GET(#JSMSTS #JSMMSG)
CHANGE FIELD(#JSMCMD) TO('DELETE FILE(')
USE BUILTIN(TCONCAT) WITH_ARGS(#JSMCMD #FILENAME ')') TO_GET(#JSMCMD)
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
 
* Now we will work on a response XML in reply to this
* order. To keep things clean, we will do this in a
* separate subroutine.
EXECUTE SUBROUTINE(RESPONSE)
 
ENDSELECT
 

* SUB ROUTINES
* The CHECK subroutine is used to capture errors returned
* from the JSM commands. For any errors encountered, a
* screen will be displayed with the error message and the
* program will exit after this.
SUBROUTINE NAME(CHECK) PARMS((#JSMSTS *RECEIVED) (#JSMMSG *RECEIVED))
 
IF COND('#JSMSTS *NE OK')
DISPLAY FIELDS(#JSMSTS #JSMMSG)
 
USE BUILTIN(JSM_CLOSE) TO_GET(#JSMSTS #JSMMSG)
 
MENU MSGTXT('Java service error has occured')
 
ENDIF
 
ENDROUTINE
 
* The ARCHIVE subroutine will build the file name and
* path for the ARCHIVE keyword of the READ command.
SUBROUTINE NAME(ARCHIVE)
USE BUILTIN(SCANSTRING) WITH_ARGS(#FILENAME 'neworders' *DEFAULT '0') TO_GET(#X_POSN)
CHANGE FIELD(#X_POSN) TO('#X_POSN + 10')
SUBSTRING FIELD(#FILENAME #X_POSN) INTO_FIELD(#ARCHIVE)
USE BUILTIN(TCONCAT) WITH_ARGS('archive/arc_' #ARCHIVE) TO_GET(#ARCHIVE)
ENDROUTINE
 
* This RESPONSE subroutine will do all the processing
* required to build and create the response XML document.
SUBROUTINE NAME(RESPONSE)
 
* The first thing we need to do is create a new empty
* outbound XML document and BIND it to the outbound
* service that we created with the XML Binding Wizard.
* Note that we specify the type as *OUTBOUND.
USE BUILTIN(JSM_COMMAND) WITH_ARGS('BIND SERVICE(OUTBOUNDRESPONSE) TYPE(*OUTBOUND)') TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
* Much of the information for the response we already
* have, but a couple of fields need to be populated so
* we will make up some fictitious data here. We will
* create some comments, and add them to a list first.
* The other new data we need to add is the LINSTAT field
* to give an indication of the status of the order line.
CLR_LIST NAMED(#LSTCMNT)
CHANGE FIELD(#COMMENTS) TO('''Thank you for your order''')
ADD_ENTRY TO_LIST(#LSTCMNT)
USE BUILTIN(BCONCAT) WITH_ARGS('We have processed your order' #SONUM 'on date:' *DDMMYYYYC) TO_GET(#COMMENTS)
ADD_ENTRY TO_LIST(#LSTCMNT)
CHANGE FIELD(#COMMENTS) TO('''Please refer below for the full details of your order.''')
ADD_ENTRY TO_LIST(#LSTCMNT)
CHANGE FIELD(#COMMENTS) TO('''One of our sales people will be in touch with you shortly.''')
ADD_ENTRY TO_LIST(#LSTCMNT)
CHANGE FIELD(#COMMENTS) TO('''For immediate assistance on your order please call 1234567''')
ADD_ENTRY TO_LIST(#LSTCMNT)
CHANGE FIELD(#COMMENTS) TO('''one more line''')
ADD_ENTRY TO_LIST(#LSTCMNT)
CHANGE FIELD(#COMMENTS) TO('''two more lines''')
ADD_ENTRY TO_LIST(#LSTCMNT)
CHANGE FIELD(#COMMENTS) TO('''three more lines''')
ADD_ENTRY TO_LIST(#LSTCMNT)
 

 
CLR_LIST NAMED(#RSPLINES)
* NOTE: The #TOGGLE field is used to alternate status
* messages - to add a bit of variety.
SELECTLIST NAMED(#ORDLINES)
IF COND('#TOGGLE = 0')
CHANGE FIELD(#TOGGLE) TO(1)
CHANGE FIELD(#LINSTAT) TO(OK)
ELSE
CHANGE FIELD(#TOGGLE) TO(0)
CHANGE FIELD(#LINSTAT) TO('OUT OF STOCK')
ENDIF
ADD_ENTRY TO_LIST(#RSPLINES)
ENDSELECT
 
* Now that we have some data, we can start using the SET
* command to populate the outbound document object. As
* per the reading of data from the order documents, since
* this example is using fragments only, we will need to
* set up loops to add any repeating data (specifically
* the comments and the order lines).
CHANGE FIELD(#JSMCMD) TO('SET FRAGMENT(ORDERRESPONSE) SERVICE_EXCHANGE(*FIELD)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
SELECTLIST NAMED(#LSTCMNT)
CHANGE FIELD(#JSMCMD) TO('SET FRAGMENT(RESPONSECOMMENTS) SERVICE_EXCHANGE(*FIELD)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
ENDSELECT
 
CHANGE FIELD(#JSMCMD) TO('SET FRAGMENT(SALESORDER) SERVICE_EXCHANGE(*FIELD)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
CHANGE FIELD(#JSMCMD) TO('SET FRAGMENT(CUSTOMER) SERVICE_EXCHANGE(*FIELD)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
SELECTLIST NAMED(#RSPLINES)
CHANGE FIELD(#JSMCMD) TO('SET FRAGMENT(LINE) SERVICE_EXCHANGE(*FIELD)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
CHANGE FIELD(#JSMCMD) TO('SET FRAGMENT(PART) SERVICE_EXCHANGE(*FIELD)')
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
ENDSELECT
 
* Now we have all the data prepared, we will serialize
* the document object out to a specified file using the
* WRITE command. We will construct a file name based on
* the customer and order number.
USE BUILTIN(TCONCAT) WITH_ARGS('response/RSP_' #CUSTNUM '_' #SONUM '.xml') TO_GET(#RESPONSE)
USE BUILTIN(TCONCAT) WITH_ARGS('WRITE FILE(' #RESPONSE ') INDENT(*YES) INDENT-AMOUNT(1)') TO_GET(#JSMCMD)
USE BUILTIN(JSM_COMMAND) WITH_ARGS(#JSMCMD) TO_GET(#JSMSTS #JSMMSG)
EXECUTE SUBROUTINE(CHECK) WITH_PARMS(#JSMSTS #JSMMSG)
 
* Finally we will CLOSE the bind then go onto the next
* XML document.
USE BUILTIN(JSM_COMMAND) WITH_ARGS(CLOSE) TO_GET(#JSMSTS #JSMMSG)
 
ENDROUTINE