SAS/IntrNet 8.2: Application Dispatcher |
The following sample Web application demonstrates some of the features of Application Dispatcher sessions. The sample application is an online library. Users can login, select one or more items to check out of the library, and request by e-mail that the selected items be delivered. The sample code shows how to create a session and then create, modify, and view macro variables and data sets in that sesssion.
This sample requires a LIB_INVENTORY data set in the SAMPDAT library that is used for other SAS/IntrNet samples. You can create the data set in Windows using the following code. You can also use the code on other systems by making the appropriate modifications to the SAMPDAT libname statement.
libname SAMPDAT '!SASROOT\intrnet\sample'; data SAMPDAT.LIB_INVENTORY; length type $10 desc $80; input refno 1-5 type 7-16 desc 17-80; datalines4; 17834 BOOK SAS/GRAPH Software: Reference 32345 BOOK SAS/GRAPH Software: User's Guide 52323 BOOK SAS Procedures Guide 54337 BOOK SAS Host Companion for UNIX Environments 35424 BOOK SAS Host Companion for OS/390 Environment 93313 AUDIO The Zen of SAS 34222 VIDEO Getting Started with the SAS System 34223 VIDEO Introduction to AppDev Studio 34224 VIDEO Building Web Applications with SAS/IntrNet Software 70001 HARDWARE Cellphone - Model 5153 70002 HARDWARE Video Project - Model 79F15 ;;;;
The initial page is the login page. This can be a static HTML page, but in this sample the login page is built at run time. The LIB_LOGIN.SAS program generates the login page as follows:
/* LIB_LOGIN.SAS - Welcome to the Online Library */ /* Print a welcome page that is static except for the Application Dispatcher variables _URL, _SERVICE, and _PGMLIB. */ data _null_; file _webout; put '<HEAD>'; put '<TITLE>Welcome to the Online Library</TITLE>'; put '</HEAD>'; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put "<H1 ALIGN=CENTER>Welcome to the Online Library</H1>"; put '<HR>'; put "<P>This is a demonstration of SAS/IntrNet Application Dispatcher sessions.</P>"; put '<P>Before you can start, you must log in. Enter your login ID below: </P>'; put '<FORM ACTION="' "&_url" '">'; put '<INPUT TYPE="HIDDEN" NAME="_service" VALUE="' "&_service" '">'; put '<INPUT TYPE="HIDDEN" NAME="_program" VALUE="' "&_pgmlib" '.lib_main.sas">'; put 'Login ID: <INPUT SIZE=12 NAME="loginid"><P>'; put 'Password: <INPUT SIZE=12 TYPE="password" NAME="password"><P>'; put '<INPUT TYPE="SUBMIT" VALUE="Login">'; put '<INPUT TYPE="RESET" VALUE="Reset">'; put '</FORM>'; put '</BODY>'; put '</HTML>'; run;
The LIB_LOGIN.SAS program generates the following page:
The login page is generated dynamically. The FORM ACTION= attribute, the _SERVICE value, and the _PROGRAM library name are all generated at run time based on Application Server macro variables. This enables you to move the application to different Web servers, Application Dispatcher services, or program libraries without editing static HTML. Only the URL for the initial login page changes.
The login page allows the user to enter a login ID and password. Clicking the Login button runs the LIB_MAIN.SAS program in order to verify the input data, create a session, and display the Main Aisle page.
The main aisle page is generated by the LIB_MAIN.SAS program. The LIB_MAIN program also verifies the information that is supplied from the login page.
/* LIB_MAIN.SAS - Main Aisle of the Online Library */ /* Use a macro here in order to use conditional logic. */ %macro lib_main; /* Check to see if you are already in a session; if so, you don't need to validate login info. */ %if %sysfunc(libref(SAVE)) %then %do; /* SAVE libref doesn't exist, so you have not successfully logged in. */ /* Insert logic here in order to validate the login ID and password. For the purposes of this sample, assume that any non-blank password is valid. This is not usually a good idea; a real application can be expected to insert some real validation logic here. */ %if &password ne %then %let IDCHECK=PASSED; %else %let IDCHECK=FAILED; %if &IDCHECK ne PASSED %then %do; /* Validation failed - print a failure page. */ data _null_; file _webout; put '<HTML>'; put '<HEAD><TITLE>Invalid Login</TITLE></HEAD>'; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put '<H1>Invalid Login</H1>'; put; put '<P>The login ID and password that you supplied are invalid. Please'; put 'return to the <A HREF="' @; put "&_URL?_SERVICE=&_service" '&_program=' "&_pgmlib" @; put '.lib_login.sas">login page</a> and re-enter a valid login ID'; put 'and password.</P>'; put; put '<P>If you are unable to login, please contact the Library Help'; put 'at extension 14325.</P>'; put '</BODY></HTML>'; run; %end; %else %do; /* Validation successful - create session and save login ID. */ %let rc=%sysfunc(appsrv_session(create)); %global SAVE_LOGINID; /* SAVE_* variables must be global. */ %let SAVE_LOGINID=&loginid; /* Save the login ID in the session. */ %end; %end; %else %let IDCHECK=PASSED; /* Assume valid login if session already exists. */ %if &IDCHECK eq PASSED %then %do; /* Print the Main Aisle page. */ data _null_; file _webout; put '<HTML>'; put '<HEAD><TITLE>Online Library Main Aisle</TITLE></HEAD>'; put; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put '<H1>Online Library Main Aisle</H1>'; put; put 'Select one of the following areas of the library:'; put '<UL>'; length hrefroot $400; hrefroot = "%superq(_THISSESSION)" || '&_PROGRAM=' || "&_PGMLIB"; put '<LI><A HREF="' hrefroot +(-1) '.lib_aisle.sas&type=Book">Book Aisle</A></LI>'; put '<LI><A HREF="' hrefroot +(-1) '.lib_aisle.sas&type=Video">Video Aisle</A></LI>'; put '<LI><A HREF="' hrefroot +(-1) '.lib_aisle.sas&type=Audio">Audio Aisle</A></LI>'; put '<LI><A HREF="' hrefroot +(-1) '.lib_aisle.sas&type=Hardware">Hardware Aisle</A></LI>'; put '<LI><A HREF="' hrefroot +(-1) '.lib_cart.sas">View my shopping cart</A></LI>'; put '<LI><A HREF="' hrefroot +(-1) '.lib_logout.sas">Logout</A></LI>'; put '</UL>'; put '</BODY>'; put '</HTML>'; run; %end; %mend; %lib_main;
You should display the main aisle page only if the user has logged in; therefore, the first step is to verify user login. First, verify that a session already exists. If the session exists (which is verified by testing whether the SAVE libref exists), then you know that the user has already logged in and you can allow the user to view the main aisle page section of the program.
If the session does not exist, then you can verify valid login information. This sample requires a non-blank login ID and password. If a valid login ID and password are not supplied, the program will display an invalid login page and redirect the user to the login page.
If the supplied login ID and password are valid, the program will create a session and then save the LOGINID value in a session macro variable that is named SAVE_LOGINID. Because the SAVE_LOGINID is declared as a global variable and its name begins with SAVE_, it will be saved for the duration of the session.
After the program verifies that the user has logged in, the main aisle page is displayed. The main aisle page consists of a list of links to specific sections of the Online Library.
Each link in this page is built using the _THISSESSION macro variable. This variable includes all of the values that are necessary in order to run another Application Dispatcher program in the same session. Use the %SUPERQ function to quote the _THISSESSION variable; this prevents the variable's ampersand characters from being interpreted as SAS macro variables.
Note: By default, sessions are identified entirely in the URLs or HTML form fields that reference the session. You can use the SESSION VERIFY option to provide an increased level of session security.
The library is divided into aisles for different categories of library items. The pages for each aisle are generated by one shared LIB_AISLE.SAS program. The program accepts a TYPE input variable that determines which items to display.
/* LIB_AISLE.SAS - List items in a specified aisle. The aisle is specified by the TYPE variable. */ %macro lib_aisle; /* Check for a valid session - verifies that the user has logged in. */ %if %sysfunc(libref(SAVE)) %then %do; /* SAVE libref doesn't exist - redirect to login page. */ data _null_; file _webout; put '<HTML>'; put '<HEAD><TITLE>Missing Login</TITLE></HEAD>'; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put '<H1>Missing Login</H1>'; put; put '<P>You must login before you can use this application. Please'; put 'return to the <A HREF="' @; put "&_URL?_SERVICE=&_service" '&_program=' "&_pgmlib" @; put '.lib_login.sas">login page</a> and enter a valid login ID'; put 'and password.</P>'; put; put '<P>If you are unable to log in, please contact the Library Help'; put 'at extension 14325.</P>'; put '</BODY></HTML>'; run; %end; %else %do; /* Build a temporary data set that contains the selected type, and add links for selecting and adding items to the shopping cart. */ data templist; set SAMPDAT.LIB_INVENTORY; where type="%UPCASE(&type)"; length select $200; select = '<A HREF="' || "%superq(_THISSESSION)" || '&_program=' || "&_PGMLIB" || '.LIB_ADDITEM.SAS&REFNO=' || trim(left(refno)) || '&TYPE=' || "&TYPE" || '">Add to cart</A>'; run; ods html body=_webout(nobot) rs=none; title Welcome to the &type Aisle; proc print data=templist noobs label; var refno desc select; label refno='RefNo' desc='Description' select='Select'; run; ods html close; data _null_; file _webout; put '<P>'; put 'Return to <A HREF="' "%SUPERQ(_THISSESSION)" '&_PROGRAM=' "&_PGMLIB" '.LIB_MAIN.SAS">main aisle</A><BR>'; put 'View my <A HREF="' "%SUPERQ(_THISSESSION)" '&_PROGRAM=' "&_PGMLIB" '.LIB_CART.SAS">shopping cart</A><BR>'; put '</BODY>'; put '</HTML>'; run; %end; %mend; %lib_aisle;
The program selects a subset of the LIB_INVENTORY data set using a WHERE clause, and then uses PROC PRINT to create an HTML table. A temporary data set is created that contains the selected items in order for an additional column to be generated that has an HTML link for users to add the item to their shopping cart.
In this program, both ODS and a DATA step are used to generate HTML. The ODS HTML statement includes the NOBOT option that indicates that more HTML will be appended after the ODS HTML CLOSE statement. The navigation links are then added using a DATA step.
The LIB_ADDITEM.SAS program is run when the user clicks the Add to cart link in the aisle item table. The specified item is copied from the LIB_INVENTORY data set to a shopping cart data set in the session library (SAVE.CART). The session and the data set will remain accessible to all programs in the same session until the session is deleted or it times out.
/* LIB_ADDITEM.SAS - Add a selected item to the shopping cart. This program uses REFNO and TYPE input variables to identify the item. */ /* Perform REFNO and TYPE verification here. */ /* Append the selected item. */ proc append base=SAVE.CART data=SAMPDAT.LIB_INVENTORY; where refno=&refno; run; /* Print the page. */ data _null_; file _webout; put '<HTML>'; put '<HEAD><TITLE>Selected Item Added to Shopping Cart</TITLE></HEAD>'; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put "<H1>Item &refno Added</H1>"; put 'Return to <A HREF="' "%SUPERQ(_THISSESSION)" '&_PROGRAM=' "&_PGMLIB" '.LIB_AISLE.SAS&TYPE=' "&TYPE" '">' "&TYPE aisle</A><BR>"; put 'Return to <A HREF="' "%SUPERQ(_THISSESSION)" '&_PROGRAM=' "&_PGMLIB" '.LIB_MAIN.SAS">main aisle</A><BR>'; put 'View my <A HREF="' "%SUPERQ(_THISSESSION)" '&_PROGRAM=' "&_PGMLIB" '.LIB_CART.SAS">shopping cart</A><BR>'; put '</BODY>'; put '</HTML>'; run;
The program prints an information page that has navigation links.
The LIB_CART.SAS program displays the contents of the shopping cart.
/* LIB_CART.SAS - Display contents of the shopping cart (SAVE.CART data set). */ %macro lib_cart; %let CART=%sysfunc(exist(SAVE.CART)); %if &CART %then %do; /* This program could use the same technique as the LIB_AISLE program in order to add a link to each line of the table that removes items from the shopping cart. */ /* Print the CART contents. */ ods html body=_webout(nobot) rs=none; title Your Selected Items; proc print data=SAVE.CART noobs label; var refno desc; label refno='RefNo' desc='Description'; run; ods html close; %end; %else %do; /* No items in the cart. */ data _null_; file _webout; put '<HTML>'; put '<HEAD><TITLE>No items selected</TITLE></HEAD>'; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put '<H1>No Items Selected</H1>'; put; run; %end; /* Print navigation links. */ data _null_; file _webout; put '<P>'; if &CART then do; put '<FORM ACTION="' "&_url" '">'; put '<INPUT TYPE="HIDDEN" NAME="_service" VALUE="' "&_service" '">'; put '<INPUT TYPE="HIDDEN" NAME="_program" VALUE="' "&_pgmlib" '.LIB_LOGOUT.SAS">'; put '<INPUT TYPE="HIDDEN" NAME="_server" VALUE="' "&_server" '">'; put '<INPUT TYPE="HIDDEN" NAME="_port" VALUE="' "&_port" '">'; put '<INPUT TYPE="HIDDEN" NAME="_sessionid" VALUE="' "&_sessionid" '">'; put '<INPUT TYPE="HIDDEN" NAME="CHECKOUT" VALUE="YES">'; put '<INPUT TYPE="SUBMIT" VALUE="Request these items">'; put '</FORM><P>'; end; put 'Return to <A HREF="' "%SUPERQ(_THISSESSION)" '&_PROGRAM=' "&_PGMLIB" '.LIB_MAIN.SAS">main aisle</A><BR>'; put '<A HREF="' "%SUPERQ(_THISSESSION)" '&_PROGRAM=' "&_PGMLIB" '.LIB_LOGOUT.SAS&CHECKOUT=NO">Logout</A><BR>'; put '</BODY>'; put '</HTML>'; run; %mend; %lib_cart;
The contents of the shopping cart are displayed using a PROC PRINT statement. The page also includes a request button and navigation links. The request button is part of an HTML form. In order to connect to the same session, include _SERVER, _PORT, and _SESSIONID values in addition to the normal _SERVICE and _PROGRAM values. These values are usually specified as hidden fields and set to the corresponding SAS macro variables. This program has a hidden CHECKOUT field that is initialized to YES in order to indicate that the user is requesting the items in the cart.
The LIB_LOGOUT.SAS program checks the user out of the Online Library. If the CHECKOUT input variable is YES, then all of the items in the user's shopping cart will be requested via e-mail.
/* LIB_LOGOUT.SAS - logout of Online Library application. Send e-mail to the library@abc.com account with requested item if CHECKOUT=YES is specified. */ %macro lib_logout; %global CHECKOUT; /* Define CHECKOUT in case it was not input. */ %if %UPCASE(&CHECKOUT) eq YES %then %do; /* Checkout - send an e-mail request to the library. E-mail options must be specified in order for the Application Server to use the e-mail access method. */ filename RQST EMAIL 'library@abc.com' SUBJECT='Online Library Request for &SAVE_LOGINID'; ods listing body=RQST; title Request for &SAVE_LOGINID; proc print data=SAVE.CART label; var refno type desc; label refno='RefNo' type='Type' desc='Description'; run; ods listing close; data _null_; file _webout; put '<HTML>'; put '<HEAD><TITLE>Library Checkout</TITLE></HEAD>'; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put '<H1>Library Checkout</H1>'; put; put 'The items in your shopping cart have been requested.'; put '<P>Requested items will normally arrive via interoffice'; put 'mail by the following day. Thank you for using the Online Library.'; put '<P><A HREF="' "&_URL?_SERVICE=&_SERVICE" '&_PROGRAM=' "&_PGMLIB" '.LIB_LOGIN.SAS">Click here</A> to re-enter the'; put 'application.'; put '</BODY>'; put '</HTML>'; run; %end; %else %do; /* Logout without requesting anything. */ data _null_; file _webout; put '<HTML>'; put '<HEAD><TITLE>Logout</TITLE></HEAD>'; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put '<H1>Library Logout</H1>'; put; put '<P>Thank you for using the Online Library.'; put '<P><A HREF="' "&_URL?_SERVICE=&_SERVICE" '&_PROGRAM=' "&_PGMLIB" '.LIB_LOGIN.SAS">Click here</A> to re-enter the'; put 'application.'; put '</BODY>'; put '</HTML>'; run; %end; %mend; %lib_logout; /* User is finished - delete the session. */ %let rc=%sysfunc(appsrv_session(delete));
An information page is displayed if the user chooses to request the shopping cart items.
A simple logout screen is displayed if the user selects the Logout link.
Note: Logging out is not required. All sessions have an associated timeout (the default is 15 minutes). If the session is not accessed for the duration of the timeout, the session and all temporary data in the session will be deleted. In this sample, the SAVE.CART data set and the SAVE_LOGINID macro variable would be automatically deleted when the session timeout is reached. You can change the session timeout using the TIMEOUT option of the PROC APPSRV SESSION statement or by using the APPSRV_SET('session timeout',seconds) function inside the program.
Users of the Online Library application might see an invalid session Application Error page. An invalid session might happen for the following reasons:
The default invalid session page is not very useful to the typical user because it does not provide specific information.
You can replace the default page by using the INVSESS option of the PROC APPSRV SESSION statement. The INVSESS option specifies a program that will run when the Application Server finds a nonexistent (invalid or expired) session. Note that the INVSESS program applies to all applications that use a particular Application Dispatcher service. The INVSESS program can use the _USERPROGRAM variable to determine which program or application the user was attempting to run, and then print a suitable error page. An INVSESS program for the Online Library application follows:
/* LIB_INVSESS.SAS - Display useful message for expired or invalid sessions. */ %macro lib_invsess; %if %upcase(%substr(%scan(&_USERPROGRAM,2,.),1,4)) eq LIB_ and %upcase(%scan(&_USERPROGRAM,3,.)) eq SAS %then %do; /* If the program name (second part of three part name) starts with LIB_ and the program type (third part) is SAS, then this is the On-Line Library application and you can print an application-specific message. */ data _null_; file _webout; put '<HTML>'; put '<HEAD><TITLE>Session Expired</TITLE></HEAD>'; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put '<H1>Session Expired</H1>'; put; put 'Your connection to the Online Library has expired. You must'; put 'login again.'; put '<P>'; put '<A HREF="' "&_URL?_SERVICE=&_SERVICE" '&_PROGRAM=' "%scan(&_USERPROGRAM,1,.).LIB_LOGIN.SAS" '">Click here</A> to login.'; put '</BODY>'; put '</HTML>'; run; %end; %else %do; /* Otherwise, this is an unknown application; print a generic error page. */ data _null_; file _webout; put '<HTML>'; put '<HEAD><TITLE>Invalid or Expired Session</TITLE></HEAD>'; put '<BODY vlink="#004488" link="#0066AA" bgcolor="#E0E0E0">'; put '<H1>Invalid or Expired Session</H1>'; put; put 'Your application session has expired. In order to continue,'; put 'you must restart this application.'; put '</BODY>'; put '</HTML>'; run; %end; %mend; %lib_invsess;
After the Application Server is configured to use the LIB_INVSESS.SAS program, an expired session message for the Online Library application will display:
SAS/IntrNet 8.2: Application Dispatcher |