PDFSpoolFileService Example
This example program will perform the following steps:
1. Executes an OVRPRTF command and a WRKJOB command to create a spooled file on output queue QPRINT in QGPL with user data PDFSPLF.
2. Performs a series of calls necessary to load the PDFSpoolFileService and connect to the IBM i host machine.
3. Retrieves a list of spool files from output queue QPRINT in QGPL with user data PDFSPLF.
4. Converts the first spool file in the list to the PDF file PDFSPLF.PDF in the JSM instance root folder (this may not be the spool file created by the current run if the program has been run before without cleaning up previous spool files).
5. Disconnects, unloads the service and closes the connection to the JSM server.
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 LIST command of the PDFSpoolFileService passes a multiple occurrence data structure in which it will receive a list of up to 50 spool files on the specified output queue. 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. Recent installations of LANSA Integrator will already contain this structure XML. If not 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 PDFSpoolFileList.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="SPFNAM" type="A" length="10" />
<rdml:field name="SPFNUM" type="A" length="6" />
<rdml:field name="JOBNAM" type="A" length="10" />
<rdml:field name="JOBUSR" type="A" length="10" />
<rdml:field name="JOBNUM" type="A" length="6" />
<rdml:field name="SPFSTS" type="A" length="10" />
</rdml:structure>
3. Register the structure XML with the JSM Server
The example program below refers to the structure XML supplied above with the symbolic name PDFSPLF.SpoolFileList by specifying that name in the SERVICE_STRUCTURE keyword of the 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. Recent installations of LANSA Integrator will already contain this link. Otherwise, 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.PDFSPLF.SpoolFileList=structure/PDFSpoolFileList.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.
*************************************************
* PDFSPLF: example in RPG ILE of using the LANSA Integrator
* PDFSpoolFileService
*
* 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>/PDFSPLF)
* SRCFILE(<srclib>/<srcfil>)
*
* CRTPGM PGM(<pgmlib>/PDFSPLF)
* MODULE(<modlib>/PDFSPLF)
* BNDSRVPGM(<jsmpgmlib>/DCXS882X)
* ACTGRP(*CALLER)
*************************************************
* Commands to create the spooled file used by this program
d ovrprt c const('OVRPRTF FILE(QPDSPJOB) +
d OUTQ(QGPL/QPRINT) HOLD(*YES) +
d USRDTA(PDFSPLF)')
d wrkjob c const('WRKJOB OUTPUT(*PRINT)')
d ovrprtlen c const(%len(ovrprt))
d wrkjoblen c const(%len(wrkjob))
* 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 receive spool file list
* - the structure must contain the following fields as defined
* by the LIST command of the PDFSpoolFileService
* o Spool file name
* o Spool file number
* o Job name
* o Job user
* o Job number
* o Spool file status
* NB: This MUST match the structure xml provided to the JSM Server!
d spoollist ds occurs(spoolocur)
d spoolfnam 10a
d spoolfnum 6a
d spooljnam 10a
d spooljusr 10a
d spooljnum 6a
d spoolfsts 10a
d spoolocur c const(50)
d spoolsize c const(%size(spoollist))
d spoolcount s 9p 0 inz(0)
* Completion messages
d CompMsg10 c 'JSMOPEN call completed.'
d CompMsg20 c ' SERVICE_LOAD call completed.'
d CompMsg30 c ' CONNECT call completed.'
d CompMsg40 c ' LIST call completed.'
d CompMsg50 c ' CREATE call completed.'
d CompMsg60 c ' DISCONNECT call completed.'
d CompMsg70 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
* Create a spool file that we will convert to PDF
c call 'QCMDEXC'
c parm ovrprt command 255
c parm ovrprtlen commandlen 15 5
c call 'QCMDEXC'
c parm wrkjob command 255
c parm wrkjoblen commandlen 15 5
* 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 PDFSpoolFileService
* - this example explicitly turns tracing on, overriding the
* settings in the manager.properties file
c eval jsmcmd = 'SERVICE_LOAD'
c + ' SERVICE(PDFSPOOLFILESERVICE) TRACE(*YES)'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg20:'*COMP')
* Connect to the IBM i host machine containing the required spool files
* - because no HOST parameter is specified, the service will establish
* the connection to the same IBM i that the JSM Server is running on
c eval jsmcmd = 'CONNECT'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg30:'*COMP')
* Load a list of spool files on the QGPL/QPRINT output queue
* - although this passes the multiple occurrence data structure
* (spoollist) 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 PDFSpoolFileService 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 = 'LIST'
c + ' LIBRARY(QGPL) QUEUE(QPRINT)'
c + ' USERDATA(PDFSPLF)'
c + ' SERVICE_STRUCTURE('
c + 'PDFSPLF.SpoolFileList)'
c + ' OCCURS(' + %char(spoolocur) + ')'
c + ' SIZE(' + %char(spoolsize) + ')'
c eval %occur(spoollist) = 1
c eval bytelength = spoolocur * spoolsize
c callp p_jsmcmdx(jsmcmd:spoollist:bytelength:
c jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg40:'*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 <= spoolocur * spoolsize)
* ... receive the spool file list into
* our multiple occurrence data structure
* - don't forget to set the DS occurrence to 1 before the call
c callp p_jsmbyterecv(spoollist)
* ... calculate the number of entries
* - for illustration only, not used in this example program
c eval spoolcount = bytelength / spoolsize
* ... create a PDF file in the root of the IFS for the first
* spool file (if any)
c eval jsmcmd = 'CREATE'
c + ' DOCUMENT(PDFSPLF.PDF)'
c + ' NAME(' + %trim(spoolfnam) + ')'
c + ' JOBNAME(' + %trim(spooljnam) + ')'
c + ' JOBUSER(' + %trim(spooljusr) + ')'
c + ' JOBNUMBER(' + %trim(spooljnum) + ')'
c + ' NUMBER(' + %trim(spoolfnum) + ')'
c + ' FONTSIZE(8) LEADING(8.5)'
c + ' ORIENTATION(*LANDSCAPE)'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg50:'*COMP')
c endif
* Close the current IBM i host machine connection
c eval jsmcmd = 'DISCONNECT'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg60:'*COMP')
* Unload the PDFSpoolFileService
c eval jsmcmd = 'SERVICE_UNLOAD'
c callp p_jsmcmd(jsmcmd:jsmsts:jsmmsg)
c callp CheckResult(jsmsts:jsmmsg)
c callp SendMessage(CompMsg70:'*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 seton LR
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