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.
[[#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)" } }]]
[[#wd DisplayAnythingRenderer { /AnythingInfo { "ShoppingPage" " MallEntry" " BookShop" " TrivialLiterature" " SF" " ComputerBooks" " VideoShop" " Love Stories" " Crime" " Sex" " Horror" " War" } }]]
[[#wd DisplayAnythingRenderer { /AnythingInfo { " GoBookShop" " GoVideoShop" " GoBack" " PutItemIntoCart" " RemoveItemFromCart" " EmptyCart" " PayBill" } }]]
[[#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).
[[#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.
[[#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).
[[#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;" "}" } }]]
[[#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;" "}" } }]]
[[#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>" "..." } }]]
Config.any entries for Roles, Pages, Renderers, Actions.
State handling in COAST
Uses protocoll of Action, Page