[[#wd Lookup TitleRecipe12 ]]

Overview

HTTP requests are short lived, e.g. get a html page or post some data out of a form and be done with it. This sort of interaction style assumes no relation between pages other than defined by the link structure of html pages themselves. For an application like a shopping mall you need more information to handle the interaction correctly. You need a session context that holds accumulated information over a defined set of pages and during some period of time. COAST executes every request in a session context, where you can store long lived data and accumulate the state necessary to guide the interaction of your application.

Preconditions

  1. Define the roles for your application.
    Sample:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"Guest      Is allowed to browse publicly available information"
    		"Shopper    Has acquired a shopping cart and already put items in it"
    		"PShopper   A shopper who has already identified itself (e.g. by paying a bill)"
    	}
    }]]
    
  2. Define your page scope (it doesn't have to be the final page structure).
    Sample:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"ShoppingPage"
    		"	MallEntry"
    		"	BookShop"
    		"		TrivialLiterature"
    		"		SF"
    		"		ComputerBooks"
    		"	VideoShop"
    		"		Love Stories"
    		"		Crime"
    		"		Sex"
    		"		Horror"
    		"		War"
    	}
    }]]
    
  3. Define possible interactions with your application.
    Sample:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"	GoBookShop"
    		"	GoVideoShop"
    		"	GoBack"
    		"	PutItemIntoCart"
    		"	RemoveItemFromCart"
    		"	EmptyCart"
    		"	PayBill"
    	}
    }]]
    

Steps to do:

  1. Decide whether you need subclasses of roles or can do it with the built-in Role class of COAST. You have to decide on the grounds of security considerations. If you just use a role to access a different set of pages but have no further security restrictions use the built-in role.

  2. Define the set of pages belonging to one role. Implement a HTML-Prototype of some of the pages to test your concept.
    For each page used define an entry in Config.any under the tag Pages. Since Pages have an inheritance relationship. It is possible to factor commonly used functionality into root pages.
    Sample:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"/Pages {"
    		"	/Page { # the root of all pages"
    		"		/ShoppingPage {     # specialized shopping page"
    		"			EntryPage           # entrance into the shopping mall"
    		"			/VideoShopPage {    # the video section of the mall"
    		"				# specialized video shop pages"
    		"				LoveStory Sex Crime Horror War"
    		"			}"
    		"			/BookShopPage {     # the book section of the mall"
    		"				# specialized book shop pages"
    		"				TrivialLit SF ComputerBooks"
    		"			}"
    		"			BillPage"
    		"		}"
    		"		/AdvertisingPage {      # advertising pages to draw in people passing by"
    		"			NewMovies NewBooks"
    		"		}"
    		"		GeneralInformation"
    		"		RelatedLinks"
    		"	}"
    		"}"
    	}
    }]]
    
    For each page you have to associate a configuration file. Therein you define the structure of the pages and dynamic elements of the pages. Try to factor commonly used elements into root pages. Use HTML-Templates to define the page structure (see [[#wd Lookup Recipe4 ]] and [[#wd Lookup Recipe5 ]] for details).

  3. Define the navigation actions of your application and implement it in the action page map of the role. For each role you need to define the action-page map in the config file 'RoleName'.any.
    Sample:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"#---- Action/Page Map -------------------------------------------------------------"
    		"/Map {"
    		"	/Default {	# list the actions available for all pages "
    		"		/Home          EntryPage"
    		"		/GoBookShop    BookShopPage"
    		"		/GoVideoShop   VideoShopPage"
    		"		/GoPayTheBill  BillPage"
    		"	}"
    		" "
    		"	# list the specific action/page maps"
    		"	/EntryPage         { ... }"
    		"	/BookShopPage      { ... }"
    		"	..."
    		"}"
    	}
    }]]
    
    If you use more than one role you have to define the actions that trigger role changes. Define them in the Config.any file under the tag RoleChanges.
    Sample:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"/RoleChanges {"
    		"	/CartGrabbed    Shopper"
    		"	/BillPayed      PShopper"
    		"	/CartEmptied    Guest"
    		"}"
    	}
    }]]
    
    If you have decided that you need some custom-made roles, implement the C++- subclasses with the relevant security hooks (see [[#wd Lookup Recipe8 ]] and [[#wd Lookup Recipe9 ]] for details).

  4. Define the actions triggering state changes in your application. Implement these actions as subclasses of C++-Class Action.
    Sample:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"class PutItemIntoCart : public ShoppingAction {"
    		"	public:"
    		"		PutItemIntoCart();"
    		"		~PutItemIntoCart();"
    		"		bool DoAction(String &action, Context &c);"
    		"};"
    	}
    }]]
    
    Implement the DoAction routine. Here you are able to store away necessary session state for later use:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"bool PutItemIntoCart::DoAction(String &action, Context &c)"
    		"{"
    		"	Anything roleStore(c.GetRoleStore());	// fetch the actives role store"
    		"	Anything tmpStore(c.GetTmpStore());		// fetch the temporary store"
    		"	Anything queryStore(c.GetQuery());		// fetch the submitted query"
    		" "
    		"	// do whatever state changes or calculation are necessary"
    		"	// by manipulating one of the stores above"
    		"	// and by evaluating values of the submitted query"
    		"	if ( queryStore.IsDefined("ShoppingItems") )"
    		"	{"
    		"		// access the query information relevant for this action"
    		"		Anything newShoppingItems= queryStore["ShoppingItems"];"
    		" "
    		"		// do something"
    		"		for(long i= 0; i < newShoppingItems.GetSize(); i++)"
    		"		{"
    		"			roleStore["Cart"]["Items"].Append(newShoppingItems[i]);"
    		"		}"
    		"	}"
    		" "
    		"	// Set an action that triggers a valid next page."
    		"	// This return value might be unchanged that means stay"
    		"	// on the same page."
    		"	action = ...;"
    		"	"
    		"	return true;"
    		"}"
    	}
    }]]
    
  5. Define the pages that use the dynamically accumulated state to give the user feedback on his actions. If they only show data without calculation, you can use lookup renderers and html-templates to define your pages (see [[#wd Lookup Recipe4 ]]).
    If you need to do some calculation before showing your page, you have to derive a C++-class from Page and implement the Page::Preprocess Method.
    Sample:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"void ShoppingPage::Preprocess(Context &c)"
    		"{"
    		"	Anything roleStore(c.GetRoleStore());	// fetch the actives role store"
    		"	Anything tmpStore(c.GetTmpStore());		// fetch the temporary store"
    		"	Anything queryStore(c.GetQuery());		// fetch the submitted query"
    		" "
    		"	// calculate data needed for the rendering of the page"
    		"	// e.g. the total amount of your items in the cart"
    		"	Anything shoppingItems= roleStore["Cart"]["Items"];"
    		"	double totalAmount= 0;"
    		" "
    		"	for(long i= 0; i < shoppingItems.GetSize(); i++)"
    		"	{"
    		"		totalAmount += shoppingItems[i]["Price"].AsDouble();"
    		"	}"
    		" "
    		"	// store it away in the tmpStore"
    		"	// here they are available for the following renderers"
    		"	tmpStore["TotalAmount"]= totalAmount;"
    		"}"
    	}
    }]]
    
  6. Define the tags in your 'PageName'.any and 'PageName'.html files that use the dynamically calculated state.
    Sample:
    [[#wd DisplayAnythingRenderer {
    	/AnythingInfo {
    		"..."
    		"<table border=0 bgcolor="#D8E7FF" cellpadding=0 cellspacing=0>"
    		"	<td>"
    		"		Total Amount:"
    		"	<td>"
    		"	<td>"
    		"		[[#wd Lookup TotalAmount ]]	<!-- finds the value in tmpStore -->"
    		"	</td>"
    		"</table>"
    		"..."
    	}
    }]]
    

Remarks

Config.any entries for Roles, Pages, Renderers, Actions.
State handling in COAST
Uses protocoll of Action, Page

Glossary

Related Topics