Chaining Stored Processes

Why Chain Stored Processes?

Only the simplest stored process Web applications contain a single Web page. With the addition of a second and subsequent pages, you face the problem of passing information from one page to another. Typically, an application contains more than a single stored process. This means that you must find a way to connect the stored processes that compose your application and make sure that all of the data that is collected along the way is available in the appropriate places.
It is good programming practice to design applications so that they do not request the same information multiple times. Because HTTP is a stateless environment, each request is separate from all other requests. If a user enters a phone number on the first page of an application and submits the form, that phone number is available as an input parameter to the first stored process. After that stored process completes, the input parameters are lost unless they are explicitly saved. If the second or third stored process in the application needs to know the specified phone number, then the application must ask for the phone number again. There are several ways to solve this problem. You can store data values in the following locations:
  • on the client in hidden form fields or URL parameters
  • on the client in cookies
  • on the server by using sessions
Note: When you are registering each stored process in a chain, you can check the Hide from user box on the General tab in the Stored Process Properties dialog box to hide the second and subsequent stored processes in a chain from the client application. This option hides the stored process from the folder view and search results for clients like the SAS Stored Process Web Application, so the user won’t try to execute the second or subsequent stored processes in a chain directly.

Passing Data through Form Fields or URL Parameters

Storing data on the client in hidden fields or URL parameters is the simplest technique. To do this, you must dynamically generate all of the HTML pages in your application except for the initial page. Because each page functions as a mechanism for transporting data values from the previous stored process to the next stored process, it cannot be static HTML stored in a file.
Usually, the application takes the following steps:
  1. The first HTML page is a welcome or login screen for the application. After the user enters any required information, the first stored process is executed by submitting a form or clicking on a link.
  2. The first stored process performs any necessary validation on the submitted parameters and any required application initialization.
  3. The first stored process writes an HTML page to the _WEBOUT output stream. This HTML page might be an initial report or it might be the next navigation page in the application. Links in this page typically execute another stored process and pass user identity, user preferences, application state, or any other useful information through hidden form fields or URL parameters.
  4. Each succeeding link in the application executes another stored process and passes any required information through the same technique.
Each hidden field in the second form can contain one name/value pair that is passed from the first form. You should use unique names for all of the data values in the entire application. In this way, you can pass all of the application data throughout the entire application.
When you dynamically generate the second form, you can write out the name of the second stored process in the hidden field _PROGRAM. Because the first stored process contains the logic to determine the second stored process, this is referred to as chaining stored processes. A stored process can chain to multiple stored processes depending on the link that a user chooses or on data that is entered by the users. The stored process can even chain back to itself.
In the following example, the MyWebApp application starts with a static HTML welcome page:
 <!-- Welcome page for MyWebApp -->
 <HTML>
 <HEAD><TITLE>Welcome to MyWebApp
 </TITLE></HEAD>
 <BODY><H1>Welcome to MyWebApp</H1>
 <FORM ACTION="/SASStoredProcess/do">
 Please enter your first name:
 <INPUT TYPE="text" NAME="FNAME"><BR>
 <INPUT TYPE="hidden" NAME="_program" 
 VALUE="/WebApps/MyWebApp/Ask Color">
 <INPUT TYPE="submit" VALUE="Run Program">
 </FORM>
 </BODY></HTML>
This welcome page prompts the user for a first name and passes the value as the FNAME input parameter to the /WebApps/MyWebApp/Ask Color stored process, as in the following example:
 /* Ask Color stored process
 *
 * This stored process prompts for the user's favorite
 * and passes it to the Print Color stored process.
 */
 data _null_;
 file _webout;
 put '<HTML>';
 put '<H1>Welcome to MyWebApp</H1>';

 /* Create reference back to the Stored Process
 Web Application from special automatic
 macro variable _URL. */
 put "<FORM ACTION='&_URL'>";

 /* Specify the stored process to be executed using
 the _PROGRAM variable. */
 put '<INPUT TYPE="hidden" NAME="_program" ' 
 'VALUE="/WebApps/MyWebApp/Print Color">';

 /* Pass first name value on to next program.
 The value is user entered text, so you must
 encode it for use in HTML. */
 fname = htmlencode("&FNAME", 'amp lt gt quot');
 put '<INPUT TYPE="hidden" NAME="fname" VALUE="'
 fname +(-1) '"><BR>';

 put 'What is your favorite color?';
 put '<SELECT SIZE=1 NAME="fcolor">';
 put '<OPTION VALUE="red">red</OPTION>';
 put '<OPTION VALUE="green">green</OPTION>';
 put '<OPTION VALUE="blue">blue</OPTION>';
 put '<OPTION VALUE="other">other</OPTION>';
 put '</SELECT><BR>';
 put '<INPUT TYPE="submit" VALUE="Run Program">';
 put '</FORM>';
 put '</HTML>';
 run;
This stored process simply creates an HTML form that prompts the user for more information. The reserved macro variable _URL is used to refer back to the SAS Stored Process Web Application. This enables you to move the Web application without modifying each stored process. The _PROGRAM variable specifies the stored process that processes the contents of the form when it is submitted. In order to keep the FNAME that was entered in the initial page, place it in the form as a hidden field. Because the value was entered by the user, it must be encoded using the HTMLENCODE function in case it contains any character that might be interpreted as HTML syntax. The form prompts the user for a color choice and chains to a new stored process named Print Color, as in the following example:
 /* Print Color stored process
 *
 * This stored process prints the user's 
 * first name and favorite color.
 */
 data _null_;
 file _webout;
 put '<HTML>';
 fname = htmlencode("&FNAME");
 put 'Your first name is <b>' 
	 fname +(-1) '</b>';
 put '<BR>';
 put "Your favorite color is 
	 <b>&FCOLOR</b>";
 put '<BR>';
 put '</HTML>';
 run;
The Print Color stored process prints the values of the variables from both the first and second forms, illustrating that the data has been correctly passed throughout the entire application.
A variation of this technique uses URL parameters instead of hidden form fields. The following example code is an alternative implementation of the Ask Color stored process:
 /* Ask Color stored process
 *
 * This stored process prompts for the user's favorite
 * and passes it to the Print Color stored process.
 */
 data _null_;
 file _webout;
 put '<HTML>';
 put '<H1>Welcome to MyWebApp</H1>';

 /* Build a URL referencing the next stored process.
 * Use URLENCODE to encode any special characters in
 * any parameters. */
 length nexturl $500;
 nexturl = "&_URL?_program=
 /WebApps/MyWebApp/Print Color" ||
 '&fname=' || urlencode("&FNAME");

 put 'What is your favorite color?';
 put '<UL>';
 put '<LI><A HREF="' nexturl +(-1)
 '&color=red">red</A></LI>';
 put '<LI><A HREF="' nexturl +(-1)
 '&color=green">green</A></LI>';
 put '<LI><A HREF="' nexturl +(-1)
 '&color=blue">blue</A></LI>';
 put '<LI><A HREF="' nexturl +(-1)
 '&color=other">other</A></LI>';
 put '</UL>';
 put '</HTML>';
 run;
This stored process generates a separate URL link for each color choice. The end result is the same as the first implementation of Ask Color; the Print Color stored process is executed with both FNAME and COLOR input parameters.
The technique of passing data by using hidden fields or URL parameters has the following advantages:
  • simple to perform
  • easy to debug
  • state is maintained indefinitely
  • allows stored processes to be distributed across multiple servers
The major disadvantages of this technique are the necessity to use dynamically generated HTML for all pages in the application and the security and visibility of the data. The data in hidden fields is readily visible to the client by viewing the HTML source (and is directly visible in the URL when using GET method forms). The data is easily changed by the user, and falsified or inconsistent data can be submitted to the application. Sensitive data should be validated in each new stored process, even if it is passed from generated hidden fields.

Passing Data through Cookies

HTTP cookies are packets of information that are stored in the client Web browser. They are shuttled back and forth with the application requests. In a general sense, they are quite similar to hidden form fields, but they are automatically passed with every request to the application. Cookies have the advantage of being nearly invisible to the user. They contain a built-in expiration mechanism, and they are slightly more secure than hidden fields. They also work seamlessly across multiple stored process servers and Web applications and are preserved even if your application uses static HTML pages. For more information about setting and using cookies, see Set-Cookie. You must enable HTTP cookies in your Web application configuration. For more information, see Configuring the SAS Stored Process Web Application .
HTTP cookies can be complex to generate and parse. Carefully consider names, paths, and domains to ensure that your cookie values do not conflict with other applications that are installed on the same Web server. HTTP cookies can also be disabled by some clients due to privacy concerns.

Passing Data through Sessions

Sessions provide a simple way to save state on the server. Instead of passing all of the saved information to and from the Web client with each request, a single session key is passed and the data is saved on the server. Applications must use all dynamically generated HTML pages, but the hidden fields or URL parameters are much simpler to generate. In addition, sessions provide a method to save much larger amounts of information, including temporary data sets or catalogs. Sessions have the disadvantage of binding a client to a single server process, which can affect the performance and scalability of a Web application. Sessions are not recommended for simple applications that pass small amounts of data from one stored process to another. For more information, see Using Sessions.