12-29-2014 04:39 PM
I'm trying to understand the REPLAY stored process that is used by lightweight sessions.
Inspired by an example in Don Henderson's building Wed Apps for SAS/IntrNet where he writes pdf and rtf output to &_tmpcat, then uses REPLAY in links to let user download the files (p.144), without actually re-running the stored process.
I'm working on 9.3 BI stored process server with streaming results.
I couldn't find much in the docs about the REPLAY stored process to describe how it works, just this bit in Stored Process Developer's Guide:
The special macro variable _TMPCAT contains the name of the temporary catalog that is used for REPLAY entries. The variable _REPLAY contains the complete URL that is used to reference the REPLAY stored process (except the actual entry name).
Did find some SAS IntrNet docs which describe the replay program (not a STP at that point, I guess):
If you are using the _REPLAY program with Microsoft Office, then you need to build a URL that uses the _OUTPUTAPP= parameter. Supported values for the _OUTPUTAPP= parameter include EXCEL, WORD, and POWERPOINT. For example, if you specify _OUTPUTAPP=EXCEL in the URL, then the content type for the replayed output is application/vnd.ms-excel. If you need to specify the name of the file that the _REPLAY program returns, use the _CONTDISP parameter in the URL. The value of this parameter is returned as a content-disposition header.
So I'd like to get a sense of what parameters REPLAY takes, and how it works. If I can get it to trigger a file download dialog box from IE, allowing use to download rtf/pdf/tagsets.excelxp and have the header reflect Word/Acrobat/Excel, I'd be happy. And seems pretty close from just playing a bit.
Or perhaps better than documentation would be if the SAS code behind REPLAY is available somewhere? If this is really a stored process, then there is SAS code behind, it, right?
12-30-2014 05:39 PM
I've not used that _REPLAY catalog thing, but I often use a slightly simpler method to make datasets/rtfs/workbooks/whatever available as a proper pop-up download in the browser after a STP has finished executing / creating the output.
It works well, you just might have to implement your own cleanup routines to get rid of the packages for download as and when you want to get rid of them.
Hope it helps.
12-30-2014 07:59 PM
That's a nifty approach. I was thinking my options were to use light weight sessions, real sessions, or just write the reports somewhere and stream them back, as your are doing. And even if I could get the lightweight sessions working, I don't think I would trust it that much.
But your approach of having the STP call itself recursively in an iframe is nicer than my plan to have the first stored process return an html file with a link that says "download", which when clicked would invoke second stored process that streams the file back to the user. I guess the recursive part isn't actually essential. I could have a generic StreamFile stored process called in the iframe, right? So the key insight is that invoking a secondary stored process in an iframe is a way to deliver both html file and a file to download when a user submits a STP.
Had spent a while googling stuff like "serve two pages" trying to find a way to return an html file and then a pdf/excel/etc, but didn't come up with much. So thanks for this approach. Will be fun to play with.
12-30-2014 08:37 PM
Yeah, you don't need the recursive part at all - obviously you just have to make sure that your code generates the output file prior to the data step that outputs the html for the iframe, as this is the point where your second stp will be called. Also you'll need to set appropriate MIME content-type headers each time if you're using a generic StreamFile stp to serve up different file types - I think IE8 is particularly picky.
It's pretty cool though - I remember we built a pretty full on file manager using this technique a few years ago...
12-30-2014 09:37 PM
Nice. I've already got a %StreamFile macro that sets the content-type headers as I want them, according to the extension of the file being streamed. I use it in just about all of my stored processes, to enable real-time log checking. My stored process runs, and writes results to a temp file (typically html/pdf/rtf/xml) in work directory, then I check the log to see if any error messages, and if the log is clean, I call %streamfile to send the file back to _webout. I blogged about that approach on bi-notes.com (but didn't have it macroized at that point).
So with that, I should be able to make the generic StreamFile stored process pretty quickly. And will just have to add to it to do the cleanup bit, since that wasn't needed when I was writing the files to WORK directory.