How to create an HTML application that maintains user state across server failures.
You can run this technique code from:
NOTE First make sure that database is running on your localhost SilverStream Server | |
See the chapter on administering a cluster in the Administrator's Guide |
The term session-level failover refers to the ability of an HTML application to retain temporary user data (state) across server failures in a cluster. The data is stored in a persistent storage repository (such as a database or file system shared by the servers in the cluster) so that it can be recovered by any server in the cluster in the event of a server failure.
When a client makes an HTTP request against a SilverStream cluster, the Dispatcher redirects the request to an available server. After that initial connection to the Dispatcher, the user interacts directly with the server. In general, this provides better performance than having each user request go through the Dispatcher. However, because the user's browser connects directly to the server, the browser does not know what to do if the server fails.
Even if the application has maintained the user's state and it is available on another server, the browser does not know to connect to that server. If the user reconnects through the Dispatcher, an application with session-level failover will have the user's state and processing can proceed. In some cases, this level of failover is sufficient. In other cases, the application requires transparent failover. To support transparent failover, you need to use a third-party dispatcher that can automatically reroute a session to another server in the cluster.
For more information about session-level failover, see the whitepaper entitled SilverStream Session-Level Failover, which is available at the SilverStream DevCenter.
To provide session-level failover support, an HTML application uses the following classes in the SilverStream API to manage the user's state:
To retain the user's state, an HTML page calls methods on the AgoPersistentStateManager object. This object in turn calls methods associated with a business object you define that extends the AgoPersistentStoreManager class. Your business object defines the actual storage mechanism used to maintain the user's state, specifying how and where the data is stored. In the live example provided in the Examples3_HTML database, the business object that stores the data is called invPersistentStoreManager. This object is located in the com.examples.persist package. The data is stored in a table called AgPersistentState in the Examples3_HTML database.
You specify the name of the business object that provides a storage implementation for your application in a file called PersistentSession.props, which is located in the Resources subdirectory of the SilverStream installation directory. The AgoPersistentStateManager object gets the name of the storage manager object for your application by reading this file.
NOTE You do not need to define a cluster to test the live example. Simply run the pgSessionLevelFailover.html page and begin experimenting with the controls on the page. You can simulate a server failure by clicking the Simulate Server Failure button.
To retain the user's state, an HTML page calls methods on the AgoPersistentStateManager object.
Before you can read or write state data by using the AgoPersistentStateManager class, you need to call a static factory method called getPersistentStateManager()
to get a state manager object. The pgSessionLevelFailover.html page gets a state manager object in the pageRequestBegin event:
m_mgr = AgoPersistentStateManager.getPersistentStateManager(req, res, "Examples3_HTML");
The final argument to getPersistentStateManager()
specifies the name of the current application. This name is used to retrieve application-specific settings from the PersistentSession.props file, including the name of the store manager object, the cleanup age (the number of hours the state data should be retained), and the debug flag, which enables or disables debugging messages.
The AgoPersistentStateManager class has methods that let you read data from and write data to the persistent store. For example, to write the key and value data that the user enters on the page, the pgSessionLevelFailover.html page calls the put()
method in the code for the Add button's pageActionPerformed event. The call to the commit()
method tells the store manager to write the data to the persistent store:
try { //Add the key (and its value) into the persistent state manager m_mgr.put(fldKey.getText(), fldValue.getText()); //If autocommit is turned off then commit changes manually if (!chkAutoCommit.getState()) { //Commit the persistent data m_mgr.commit(); } //Refresh the dataview loadData(); } catch (Exception e) { lblErrorMsg.setText(e.toString()); }
Similarly, to read data from the store, the page calls the get()
method in the code for the page's loadData() method:
try { Vector vctState = new Vector(); Hashtable state = m_mgr.getStateHashtable(); //Get an enumeration of the hash table keys Enumeration e = state.keys(); while (e.hasMoreElements()) { Object[] obj = new Object[2]; obj[0] = e.nextElement(); obj[1] = m_mgr.get((Serializable)obj[0]); //Add the object array to the state vector vctState.addElement(obj); } //Set the result set for the row cursor m_rowCursor.setResultSet(vctState); //Tell the view where to get the data View1.setDataProvider(m_rowCursor); //Clear the data entry fields fldKey.setText(""); fldValue.setText(""); } catch (Exception e) { lblErrorMsg.setText(e.toString()); }
To add session-level failover support to an application, you need to create a business object that extends the AgoPersistentStoreManager class. Your business object defines the actual storage mechanism used to maintain the user's state.
Like an invoked business object, the AgoPersistentStoreManager class has an invoked()
method that is executed when the object is invoked. In the invoked()
method in your subclass, you need to call the invoked()
method on the superclass:
super.invoked(evt);
The invoked()
method for AgoPersistentStoreManager calls the following methods:
These three methods are defined as abstract in the AgoPersistentStoreManager class; you need to implement them in your subclass. The invPersistentStoreManager business object in the Examples3_HTML database shows sample implementations for these methods.
The PersistentSession.props file lets you specify both server-wide and application-specific property settings that apply to session-level failover. The AgoPersistentStateManager object reads this file. Here's what the file looks like:
############################################################################ # Server-wide Persistent State Properties ############################################################################ CookieDomain=none CookieName=PersistentSessionID ############################################################################ # Application specific PersistenceStoreManager Invoked Objects ############################################################################ SilverBooks.StoreManager=SilverBooks3:com.silverbooks.persist.invPersistentStoreManager SilverBooks.CleanupAge=24 SilverBooks.Debug=false Examples3_HTML.StoreManager=Examples3_HTML:com.examples.persist.invPersistentStoreManager Examples3_HTML.CleanupAge=24 Examples3_HTML.Debug=false PersistentSLFO.StoreManager=PersistentSLFO:com.examples.persist.invPersistentStoreManager PersistentSLFO.CleanupAge=24 PersistentSLFO.Debug=false
The property settings are described briefly below: