Managing Temporary HOLD Files

by Douglas Potter

HOLD files are a mechanism for storing temporary output files on the WebFOCUS Reporting Server. The lifespan of these files can range from very transient, such as files saved in the EDATEMP directory of a reporting agent for use in the same FEX (cargraph.fex as an example), to longer lasting files containing pre-calculated or pre-summarized data that may be run each night and used throughout the following day. The latter would include files saved to a specific location via a FILEDEF or APP FI statement and referred to by multiple other FEXs.

But what if I want a HOLD file returned to the browser (as in a graph or PDF)? What if I have multiple users that may be running the FEX at the same time? The Reporting Server manages the EDATEMP directories to provide isolation between reporting agents and avoid file collisions, but the directories are not generally configured as accessible via the Web server.

For many file formats, if the goal is just to return the file to the browser, a developer can use PCHOLD rather than HOLD, which results in a unique temp file on the application server being returned to the browser by WFServlet. However, not all file formats are valid with PCHOLD (dBASE, RDF). For some, notably graph formats, the processing differs for PCHOLD vs. HOLD. Perhaps I simply want to offload the work of returning potentially large PDF and Excel files from the application server.

A simple solution is to use APP HOLD BASEAPP to save the held file in baseapp (or some other app directory). That puts the file in a commonly accessible directory and it can be referenced using a URL like http://server/approot/baseapp/HOLD.png, but the simple solution has the potential to introduce some issues that can grow troublesome as the number of users as well as reports, graphs, and other held files grows.

One problem is filename collisions. When files are written to the same directory with identical filenames, the chance grows of someone else’s file overwriting mine before my browser can retrieve it, especially as the number of users grows. What if I'm populating a dashboard with multiple graphs (four or more iframes all referencing HOLD.png at the same time)? This hazard can be limited by using more descriptive names than the default of HOLD.png, for example, changing HOLD to SALES and incorporating the user name (from &IBIMR_user) into the filename to get names like joeSALES.png.

This solution works to a point, but it still has a few limitations. It doesn't work well for situations with large numbers of anonymous users (as in publicly available sites). It is also fairly easy to access information you may not have permission to view. For example, if I'm Bob and I want to see Joe's sales numbers, all I have to do is edit a URL and get joeSALES.png.

Something like the following:

-SET &RAND = RDUNIF('D4.2') *
10000000;
-SET &RANDNAME = &RAND | '.png';

If you want or need to start the names with an
alpha character, you can generate random alpha
characters such as these:

-SET &RAND2 = RDUNIF('D12.8') * 26;
-SET &RNDALPHA = DECODE &RAND2(0 'Z' 1
'A' 2 'B' 3 'C' 4 'D' 5 'E' 6 'F' 7
'G' 8 'H' 9 'I' 10 'J' 11 'K' 12 'L'
13 'M' 14 'N' 15 'O' 16 'P' 17 'Q' 18
'R' 19 'S' 20 'T' 21 'U' 22 'V' 23
'W' 24 'X' 25 'Y' 26 'Z');

Using random filenames largely eliminates the collisions (technically it’s still possible since they are random and not unique numbers, but the chance is remote), and limits a person’s ability to retrieve another user’s files (especially if you don’t allow directory listings via the Web so that they have to guess filenames).

With all the random file names, the files can start to pile up (just like any other temp directory). Putting all the temporary hold files in their own directory, such as C:\ibi\apps\ibitmp, makes it easy to schedule a job (via cron on Unix or a Scheduled Task on Windows) to delete them. On Windows, the scheduled command could be something like
C:\WINDOWS\system32\cmd.exe /C "del
C:\ibi\apps\ibitmp\*.* /Q". You could instead configure a completely separate web virtual directory outside of approot for the temporary files, which could have very limited access (read-only, no listings allowed, etc.).

To avoid needing to put multiple -SET statements at the top of every FEX (to keep life easy for the developer too), the random name generation can be placed in a separate file. This also makes it easier to maintain if you need to move the directory location at a later time. Since the file paths, names and URLs are generated by the common FEX, there is only one FEX to change (See Screen 1).

Now the report FEX just has to have a -INCLUDE to set the random name and return an HTML document with a URL pointing to the right location, looking something like Screen 2 on page 9.

-* set_temp_hold.fex
-* Sets &Vars for temporary hold files
-* generates filenames in the form of A1234567.&TMP_EXT
-* &TMP_EXT defaults to png , set to some other extension if not
-* generating PNG graphs
-* &TMP_RANDPATH returns a temporary path suitable for use like
-* FILEDEF HOLD1 DISK &TMP_RANDPATH
-* &TMP_RANDURL returns a URL that can be used to reference the
-* hold file.
-DEFAULT &TMP_EXT = 'png' ;
-SET &TMP_RAND2 = RDUNIF('D12.8') * 26;
-SET &TMP_RNDALPHA = DECODE &TMP_RAND2(0 'Z' 1 'A' 2 'B' 3 'C' 4 'D' 5 'E' 6
'F' 7 'G' 8 'H' 9 'I' 10 'J' 11 'K' 12 'L' 13 'M' 14 'N' 15 'O' 16 'P' 17
'Q' 18 'R' 19 'S' 20 'T' 21 'U' 22 'V' 23 'W' 24 'X' 25 'Y' 26 'Z');
-SET &TMP_RAND = RDUNIF('D4.2') * 10000000;
-SET &TMP_RANDNAME = &TMP_RNDALPHA | &TMP_RAND | '.' | &TMP_EXT;
-SET &TMP_RANDPATH = 'C:\ibi\apps\ibitmp\' | &TMP_RANDNAME ;
-SET &TMP_RANDURL = '/approot/ibitmp/' | &TMP_RANDNAME ;

Screen 1

If you are generating something other than a PNG graph file, such as a PDF, you would just need to add a line prior to the -INCLUDE like:

-SET &TMP_EXT = 'pdf' ;

The examples here are graph-centered, since I initially started working on this as a mechanism to make it easier to move graph generation from the application server to the Reporting Server and JSCOM3, but it also applies any time you want to return a Reporting Server-generated HOLD file to the browser while minimizing the load on the app server. Or if you want a random HOLD file name for some other reason. •

-INCLUDE SET_TEMP_HOLD.FEX
FILEDEF HOLD1 DISK &TMP_RANDPATH
GRAPH FILE CAR
SUM DEALER_COST
ACROSS MODEL
ON GRAPH HOLD AS HOLD1 FORMAT PNG
END
-RUN
-HTMLFORM BEGIN
<HTML>
<IFRAME id=iframe1 SRC="!IBI.AMP.TMP_RANDURL;"
height=100% width=100%>
</HTML>
-HTMLFORM

Screen 2

next