Page 1 of 1

pui.download

Posted: Fri Sep 04, 2015 10:13 am
by randyh
I have successfully gotten this pui.download to run within my display file. This is all happening when the event, onclick, is executing. Within java code how do I call an AS400 program to generate the pdf document first and place it on the IFS before it execute the pui.download statement?

Re: pui.download

Posted: Fri Sep 04, 2015 3:17 pm
by Scott Klement
Did you mean JavaScript code? Or, are you using Java for something? (We don't use Java in Profound UI, except for executing remote commands.)

The normal process is to code something into the PUIDNLEXIT program. Whatever you provide as an "id" to pui.download() is passed to the exit program, so it can use that information to generate the PDF and download it, it can also delete a temporary object from disk when the download is complete (if that is desired).

For example, let's say you wanted to generate an "item report" PDF file when the user clicks a button. You'd add the button to your screen as normal, but instead of using a "response", you'd code the "onclick" event to something like this:

Code: Select all

pui.download({ "id":  "itemrpt", "inline": true, "contentType": "application/pdf" });
Calling pui.download( ) will trigger the PUIDNLEXIT program, and it will pass the information (the "id", "inline" and "content type") to the exit program. The program can look something like this:

Code: Select all

      **********************************************************************************************
      *                                                                                            *
      *   Description: Profound UI File Download Exit Program                                      *
      *                                                                                            *
      *                Compile as PUIDNLEXIT in PROFOUNDUI product library using CRTBNDRPG.        *
      *                                                                                            *
      *                Return 1 in 'Allow' parameter to allow the upload, any other value will     *
      *                prevent the upload.                                                         *
      *                                                                                            *
      **********************************************************************************************
     H DFTACTGRP(*NO) ACTGRP(*CALLER)

     D InputData_t     ds                  qualified
     D                                     based(Template)
     D   fileid                     640a   varying
     D   userid                      10a
     D   ipAddr                      15a
     D   inline                       1n

     D Main            PR                  ExtPgm('PUIDNLEXIT')
     D   timingFlag                  10i 0 const
     D   inputData                         likeds(InputData_t) const
     D   stmfDir                    640a   varying
     D   stmfName                   256a   varying
     D   attName                    256a   varying
     D   contentType                255a   varying
     D   allow                        5i 0

     D Main            PI
     D   timingFlag                  10i 0 const
     D   inputData                         likeds(InputData_t) const
     D   stmfDir                    640a   varying
     D   stmfName                   256a   varying
     D   attName                    256a   varying
     D   contentType                255a   varying
     D   allow                        5i 0

     D RunItemRpt      PR
     D   tempfile                    50a   varying const

     D tmpnam          PR              *   extproc('_C_IFS_tmpnam')
     D   string                      39A   options(*omit)
     D unlink          PR            10I 0 ExtProc('unlink')
     D   path                          *   Value options(*string)

     D CmdExc          PR                  ExtPgm('QCMDEXC')
     D   cmd                      32702a   const options(*varsize)
     D   len                         15p 5 const

      /free
         allow = 0;

         if timingFlag=0;
           select;
           when inputData.fileId = 'itemrpt';
             stmfDir     = '/tmp';
             stmfName    = %subst(%str(tmpnam(*omit)):6) + '.pdf';
             attName     = 'itemReport.pdf';
             contentType = 'application/pdf';
             RunItemRpt( stmfDir + '/' + stmfName );
             allow = 1;
          when itemData.fileId = 'SOMETHING ELSE';
              // you can handle other reports/downloads here, etc...
          endsl;
        endif;
So here I'm checking for an 'id' (called "fileid" in the RPG program) containing the "itemrpt" string I gave to pui.download(). When that occurs, I know the user wants to run the item report. (the "id" doesn't necessarily have to be the filename, I can set the filenmae in the exit program to whatever I want.)

The 'tmpnam' call you see there is an IBM-supplied API that will generate a unique temporary file name that I can use. That way, I don't have to worry about another user running this report at the same time and having the name clash -- the output of tmpnam() will always be unique. I'm also using %subst() on the output of tmpnam() because it will start with "/tmp/", but the directory should go in a separate "stmfDir" parameter in this exit program, so I'm stripping off the "/tmp/" with %subst.

The "stmfDir" and "stmfName" will be the name of the file that PUI will read from the IFS to send to the browser.

The "attName" parameter is what the user will see as a filename when saving the download. I use "itemReport.pdf" for attName because it's a friendly-sounding name for an item report. (Whereas the output of tmpnam would be something like QAXJ123435 which would not be so friendly.)

This is all only done when the timingFlag=0 because the exit program is called twice. First time timingFlag=0, which means "before the download". timingFlag=1 would mean "after the download".

The "RunItemRpt" routine is something that I wrote to generate the item report -- you can write your own routine to generate a PDF in place of RunItemRpt... you can do whatever you want there, this RunItemRpt is only a simple example to give you the idea... I'm using IBM's 57xx-TS1, the free PDF tools that came out with V6R1 to make a PDF from a "regular" RPG report like this:

Code: Select all

      *++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * RunItemRpt(): Run the RPG program that generates
      *               an item report
      *++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P RunItemRpt      B
     D                 PI
     D   tempfile                    50a   varying const

     D ITM001R         PR                  ExtPgm('ITM001R')

     D cmd             s            500a   varying
      /free
         // Run the Item Report and override the output to
         //  a PDF file in the temporary name
         
         cmd = 'OVRPRTF FILE(QSYSPRT) DEVTYPE(*AFPDS) WSCST(*PDF) +
                        OVRSCOPE(*CALLLVL) +
                        TOSTMF(''' + TempFile + ''')';
         CmdExc(cmd: %len(cmd));

         ITM001R();

         cmd = 'DLTOVR FILE(QSYSPRT) LVL(*)';
         CmdExc(cmd: %len(cmd));
      /end-free
     P                 E 
Again, don't feel like you have to use the name "RunItemRpt" or code it the way I did... any way you can generate a PDF should be fine, here.. this is just an example. But, it makes a PDF and puts the output into the "tempfile" (which is the filename I made with tmpnam() before).

So this is downloaded to the browser when the PUIDNLEXIT program ends. But, then PUIDNLEXIT is called a second time with timingFlag=1. So I put the following code in the mainline (I have it right after the timingFlag=0 code in the mainline...)

Code: Select all


         if timingFlag=1 and inputData.fileId='itemrpt';
            unlink( stmfDir + '/' + stmfName );
         endif;

         *inlr = *on;
      /end-free
This code uses the unlink() API (an IBM-supplied API) to delete the temporary file (the one from tmpnam() that we created in the RunItemRpt() routine) from the IFS. This way, the temporary files are always cleaned up after the user downloads them.

So that's how I go about handling PDF downloads, I just have the exit program generate the PDF file on the fly. Mind you, there's no reason why you couldn't do a separate call to generate the PDF -- that'd work, too... but this way seems simpler and easier to understand to me.

All of that assumes, of course, that I understand your scenario. The bit about "Java" makes me wonder if I'm not understanding... but, probably you meant JavaScript.