SaSetStateVar
and SaGetStateVar
can handle most of your state requirements. If you wish to implement your own method for setting state, examine the example below.The purpose of the State Server and the use of Cookies is to maintain some knowledge of the user's identify and what he or she has done. One way of doing this is demonstrated in the Shopping Basket application shown on the Bluestone Web Page (http://www.bluestone.com). In this case the first thing that the user sees is an HTML screen, and then they make a choice which runs the server application.
This function is used to determine if a state server cookie is currently in use for the book cart, and returns the value if it is, zero otherwise To distinguish comments and code better, the comments are not listed as code here, although left in place.
int GetCartCookie() { char *cartpos; check HTTP_COOKIE environment variable to get HTTP_COOKIE list char *hcooks = getenv("HTTP_COOKIE"); parse HTTP_COOKIE list and look for a unique string used by this app if (hcooks && (cartpos = strstr(hcooks, hcookstr))) return atoi(cartpos+strlen(hcookstr)); else return 0; }If this function returns a zero then another is called to request a Cookie from the State Server. The Server returns a number - the ID of the Cookie - and the code places it into the environment variable HTTP_COOKIE.
This function should be called in the main function initial code of the server application. It will set up a new state server cookie if needed, and save the cookie number using HTTP_COOKIE
void InitCartCookie() {get state server cookie, 0 if none
int cookie = GetCartCookie(); char buff[300]; buff[0] = '\0';if state server cookie exists, do nothing special
if (cookie) { SaSetContentString(NULL); }else state server cookie doesn't exist
else {get new state server cookie
cookie = SaInternString("");save state server cookie using Set-cookie: in server application header
sprintf(buff, "Content-type: text/html\nSet-cookie: %s%d\n\n", hcookstr,cookie); SaSetContentString(buff); } }The above code obtains a new cookie. Both the foregoing pieces are called before anything else is done in the server application - they are placed into the Project start-up code.
This function should be called in the main
function final code of the server application. It will determine if an item is being added or deleted to the list being maintained by the state server and modify and re-save the list as needed
void UpdateCartInfo() { #define addIdStr "ADDTITLEID" #define removeIdStr "REMOVETITLEID"get state server cookie number from HTTP_COOKIE */
int cartnum = GetCartCookie(); char *posid; char *start = ""; char *finish; char *tid; int found = 0;get current list of IDs from state server
g_idList = SaGetCookie(cartnum);\x7fif keyword for adding ID is found in a hidden form element
if (SaGetNumInputValues(addIdStr)) {create a string to append with new ID in it */
tid = SaStrMCat("'", SaGetInputValue(addIdStr), "',", NULL);initialize global string to null, if empty */
if (!g_idList) g_idList = SaCopyString("");search global ID string for new ID
{ found = strstr(g_idList, tid) != NULL; }if ID is not found in global string
if (!found) {add new ID to global string
g_idList = SaStrMCat(g_idList,tid,NULL);update state server with new list
SaUpdateCookie(g_idList, cartnum); } }else if keyword for deleting ID is found in a hidden form element
else if (SaGetNumInputValues(removeIdStr)) {create a string to search for and delete with new ID in it
tid = SaStrMCat("'", SaGetInputValue(removeIdStr), "',", NULL);search global string for ID to be deleted
posid = strstr(g_idList, tid);if ID is first, advance global string to point past deleted ID
if (posid == g_idList) { g_idList = posid+strlen(tid); }else ID is found later in string
else if (posid > g_idList) {extract first set of IDs and last set of ids
start = strncat(start, g_idList, posid-g_idList); finish = posid+strlen(tid);concatenate first and last sets of IDs
g_idList = SaStrMCat(start, finish, NULL); }update state server with new list for SaUpdateCookie(g_idList,cartnum);
}else no keywords are found, so global string is unchanged
else {if global string is null, set to blank string
if (!g_idList) { g_idList = SaCopyString(""); } } }Using code like this, the server application first looks to see if a cookie is in use. If not, it obtains a new one from the State Server. Whenever the application exits, it sends the cookie - by name - to the HTML browser. The content of the cookie sent to the browser is the cookie ID from the Sapphire/Web State Server.
The cookie is obtained by the server application when it is re-started by getting the cookie ID from the environment; it does whatever work it needs to do, and uses the cookie ID to update the State Server. Thus maintaining the cookie identity (which one to use) is done by the browser whenever the application is not functional (between calls).