[Top] [Prev] [Next] [Bottom] [Contents]

Example: Low-Level Sapphire State Server Functions

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.

Getting Cookies

The server program first calls a routine that determines whether or not the application has a Cookie right now, or not.

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.

Updating Cookies

After all the work of the binding has been done, the Cookie needs to be updated with any changes that have resulted from the running of the server application.

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);\x7f 
if 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).



[Top] [Prev] [Next] [Bottom] [Contents]

info@bluestone.com
Copyright © 1997, Bluestone. All rights reserved.