ZipService Example
This example program will perform the following steps:
1. Performs a series of calls necessary to load the ZipService.
2. Creates a zip file called LIZIPIN.ZIP in directory /LIZIPOUT in the IFS.
3. Zips the contents of directory /LIZIPIN into the zip file and closes the file.
4. Opens the zip file again for reading.
5. Retrieves a list of zip file entries into a multiple occurrence data structure.
6. Unzips the first zip entry into the directory /LIZIPOUT.
7. Closes the zip file, unloads the service and closes the connection to the JSM server.
Note:- To test this example meaningfully you need to create the two folders /LIZIPIN and /LIZIPOUT in the IFS and then add a small selection of files to the folder /LIZIPIN. You can use any files – these are the files that will be zipped by the example program
- The example program can only successfully retrieve the zip file entries if they number 999 or less, so do not add more files than this to the folder /LIZIPIN
- For maximum compatibility, the example program can only cope with file paths up to 256 characters in length. Do not add files and folders to /LIZIPIN such that any one file path will exceed this limit. You can write your own programs to handle longer paths if necessary.
Refer to the comments and code in the example for more information.
There are three steps required to make this application work:
1. Create the structure XML
The call to the GET ENTRY(*LIST) command of the ZipService passes a multiple occurrence data structure in which it will receive a list of up to 999 zip file entries. For this to work, the LANSA Integrator service needs to know the characteristics of this structure. This is accomplished by supplying an XML file that describes the structure.
For this example, the required XML is supplied below. To install this XML you need to perform the following steps:
a. Locate the structure folder in the JSM instance folder for your JSM server
b. Create a file called ZipEntryList.xml
c. Edit the file with a text editor and paste into it the xml supplied below
Note that the field names used in the structure XML do not need to match the variable names used in the RPG program (and they do not match in this example). It is their order, types and length that are important.
<?xml version="1.0" encoding="UTF-8"?>
<rdml:structure xmlns:rdml="http://www.lansa.com/2000/XML/Function">
<rdml:field name="ZIPENT" type="A" length="256" />
</rdml:structure>
2. Register the structure XML with the JSM Server
The example program below refers to the structure XML supplied above with the symbolic name ZIP.ZipEntryList by specifying that name in the SERVICE_STRUCTURE keyword of the GET ENTRY(*LIST) command.
We need to give the JSM Server a link between that symbolic name and the actual name and location of the structure XML file created in step 1. To do this you need to perform the following steps:
a. Locate the system folder in the JSM instance folder for your JSM server.
b. Edit the file structure.properties with a text editor and paste into it the entry supplied below (make sure the new entry is on a line by itself).
c. Save your changes.
d. Restart or refresh the JSM Server instance (refer to Java Service Manager Refresh).
structure.ZIP.ZipEntryList=structure/ZipEntryList.xml
3. Create and run the ILE RPG example program
Recent installations of LANSA Integrator will already contain the source for the example program below. If not, you can copy and paste the source into a source file member.
To create the program, you need to use the CRTRPGMOD and CRTPGM commands. Make sure that you use the parameter values specified in the source member.
*************************************************
* ZIP: example in RPG ILE of using the LANSA Integrator
* ZipService
*
* Note: This is an example program containing only
* rudimentary exception handling
*
* To create this program you must execute the following commands,
* supplying the indicated parameter values and any others that are
* necessary in your installation:
*
* CRTRPGMOD MODULE(<modlib>/ZIP)
* SRCFILE(<srclib>/<srcfil>)
*
* CRTPGM PGM(<pgmlib>/ZIP)
* MODULE(<modlib>/ZIP)
* BNDSRVPGM(<jsmpgmlib>/DCXS882X)
* ACTGRP(*CALLER)
*************************************************
* IFS folders used by this program
* - to try this program you need to create these folders in your IFS
* and add one or more files to the /LIZIPIN folder
d flrzipin c const('/LIZIPIN')
d flrzipout c const('/LIZIPOUT')
d zipfilepath s 255a
* Declare variables for the JSM calls
d jsmsrv s 50a inz(*blanks)
d jsmsts s 20a inz(*blanks)
d jsmmsg s 255a inz(*blanks)
d jsmcmd s 255a inz(*blanks)
d bytelength s 10i 0 inz(*zero)
* Declare structure to send or receive zip file entries
* - the structure must contain the following fields as defined
* by the GET command of the ZipService
* o Zip entry (path and/or file names)
* NB: This MUST match the structure xml provided to the JSM Server!
d ziplist ds occurs(zipocur)
d zipentry 256a
d zipocur c const(999)
d zipsize c const(%size(ziplist))
d zipcount s 9p 0 inz(0)
* Completion messages
d CompMsg10 c 'JSMOPEN call completed.'
d CompMsg20 c ' SERVICE_LOAD call completed.'
d CompMsg30 c ' CREATE call completed.'
d CompMsg40 c ' OPEN call completed.'
d CompMsg50 c ' ADD call completed.'
d CompMsg60 c ' GET ENTRY(*LIST) call completed.'
d CompMsg65 c ' GET ENTRY(*READ) call completed.'
d CompMsg70 c ' CLOSE call completed.'
d CompMsg80 c ' SERVICE_UNLOAD call completed.'
d CompMsg99 c 'JSMCLOSE call completed.'
* Procedure prototypes
d CheckResult pr
d crjsts const like(jsmsts)
d crjmsg const like(jsmmsg)
d SendMessage pr
d smText 512a VALUE
d smType 10a VALUE
* Prototypes for the JSM calls
/COPY QRPGLESRC,JSM_PROC.H
* Open a connection to the default JSM server
* - because the server parameter is blank, details of the default
* JSM server are obtained from the data area JSMCTLDTA on IBM i
* or from the file jsmctldta.txt on other supported platforms)
c callp p_jsmopen(jsmsrv:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg10:'*COMP')
* Load the ZipService
* - this example explicitly turns tracing on, overriding the
* settings in the manager.properties file
c eval jsmcmd = 'SERVICE_LOAD'
c + ' SERVICE(ZIPSERVICE) TRACE(*YES)'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg20:'*COMP')
* Create the zip file: /LIZIPOUT/LIZIPIN.ZIP
* - we place it in the /LIZIPOUT folder
* - we will zip the contents of /LIZIPIN into it
c eval zipfilepath = flrzipout + flrzipin + '.ZIP'
c eval jsmcmd = 'CREATE'
c + ' FILE(' + %trim(zipfilepath) + ')'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg30:'*COMP')
* Add the contents of the folder /LIZIPIN to the zip file
* - by specifying BASE(*CURRENT) we request that path information stored
* in the zip entries is only for descendant folders of /LIZIPIN
c eval jsmcmd = 'ADD'
c + ' PATH(' + flrzipin + ') BASE(*CURRENT)'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg50:'*COMP')
* Close the current archive
c eval jsmcmd = 'CLOSE'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg70:'*COMP')
* Reopen the zip file: /LIZIPOUT/LIZIPIN.ZIP
* - we will retrieve a list of its contents
* - we will unzip the first file into /LIZIPOUT
c eval jsmcmd = 'OPEN'
c + ' FILE(' + %trim(zipfilepath) + ')'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg40:'*COMP')
* Load a list of zip entries from the current archive
* - although this passes the multiple occurrence data structure
* (ziplist) in which to receive the list, the data is not actually
* received into the structure until the JSMBYTERECV call below
* - the structure is described to the ZipService by the
* structure XML identified by the SERVICE_STRUCTURE keyword - there
* must be a matching entry in the structure.properties file and a
* corresponding structure XML file, usually in the JSMInstance\Structure
* folder
* NOTE: this call uses the JSMCMDX api in order to be able to send and/or
* receive variable data (in this case the list)
c eval jsmcmd = 'GET ENTRY(*LIST)'
c + ' SERVICE_STRUCTURE(ZIP.ZipEntryList)'
c + ' OCCURS(' + %char(zipocur) + ')'
c + ' SIZE(' + %char(zipsize) + ')'
c eval %occur(ziplist) = 1
c eval bytelength = zipocur * zipsize
c callp p_jsmcmdx(jsmcmd:ziplist:bytelength:
c jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg60:'*COMP')
* Get the length of the received data structure
* - only continue to attempt to receive it if the length is valid
c callp p_jsmbytelngth(bytelength)
c if (bytelength > 0)
c and (bytelength <= zipocur * zipsize)
* ... receive the zip entry list into
* our multiple occurrence data structure
* - don't forget to set the DS occurrence to 1 before the call
c callp p_jsmbyterecv(ziplist)
* ... calculate the number of entries
c eval zipcount = bytelength / zipsize
* ... unzip the first entry only into /LIZIPOUT
c eval jsmcmd = 'GET ENTRY(*READ)'
c + ' FILE(' + %trim(zipentry) + ')'
c + ' TO(' + flrzipout + ')'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg65:'*COMP')
c endif
* Close the current archive
c eval jsmcmd = 'CLOSE'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg70:'*COMP')
* Unload the ZipService
c eval jsmcmd = 'SERVICE_UNLOAD'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg80:'*COMP')
* Close the connection to the JSM server and finish
c callp p_jsmclose(jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg99:'*COMP')
c eval *inlr = *on
c return
*************************************************
* Procedure to check the result of a Java Service Manager call
*************************************************
p CheckResult b
d CheckResult pi
d crjsts const like(jsmsts)
d crjmsg const like(jsmmsg)
d crText s 512a
d crMsg1 c const('JSM Status : ')
d crMsg2 c const('JSM Message: ')
d crMsg3 c const('JSM Service error has +
d occurred')
c if crjsts <> 'OK'
c eval crText = crMsg1 + crjsts
c callp SendMessage(crText:'*DIAG')
c eval crText = crMsg2 + crjmsg
c callp SendMessage(crText:'*DIAG')
c callp SendMessage(crMsg3:'*ESCAPE')
c endif
p CheckResult e
*************************************************
* Procedure to send a program message
*************************************************
p SendMessage b
d SendMessage pi
d smText 512a VALUE
d smMsgT 10a VALUE
d smMsgI s 7a inz('CPF9897')
d smMsgF s 20a inz('QCPFMSG *LIBL ')
d smDtaL s 10i 0 inz(%size(smText))
d smStkE s 10a inz('*')
d smStkC s 10i 0 inz(1)
d smMsgK s 4a
d smErrC s 10i 0 inz(0)
c if smMsgT = '*ESCAPE'
c eval smMsgI = 'CPF9898'
c endif
c call 'QMHSNDPM'
c parm smMsgI
c parm smMsgF
c parm smText
c parm smDtaL
c parm smMsgT
c parm smStkE
c parm smStkC
c parm smMsgK
c parm smErrC
p e