Application State

Application state is information (properties and values) stored as an XML-like tree hierarchy which resides on both the service and the client, and its main purpose is to provide a synchronized data store between these components.

Most of the development effort when working with application state involves getting and setting the values. The PureWeb SDK automatically handles the intricacies of synchronizing state among the service and the clients.

Application state is especially well suited to the following situations:

  • for information relevant to every client and service in a session

  • for information which is really stateful and doesn’t have the characteristics of an event
  • to communicate from a single client to the service, if it is important that all other clients are aware of this communication

The content of application state is the same on the service and all connected clients in a session; participants in a collaboration session have access to all data in application state.

For sensitive data which shouldn't be shared during collaboration, you can use session storage instead; this feature allows you to maintain private synchronized data stores individually for each user session.

For storing and sharing binary objects such as word processing documents, see Resource Manager.

The best tool to monitor the application state for your application is the AppState tab of the Diagnostics Panel.

Application State Tree

The application state tree consists of two types of elements:

  • PureWeb-specific elements. These elements are entirely maintained by the PureWeb SDK. You should not attempt to change them yourself.
  • User-defined elements. What information you choose to store in application state depends entirely on the requirements of your application. The format is very flexible: it can contain basically anything that can be stored as an XML element or collection of elements. A basic use case is to store interface element properties: whether a checkbox is enabled or visible, the color of an element on the screen, and so on.

In the sample application state tree below, there is only one user-defined element: <ScribbleColor>.

<ApplicationState xmlns:typeless="http://calgaryscientific.com/typeless/2008">
    <PureWeb>
        //list of PureWeb-specific elements
    </PureWeb>
    <ScribbleColor>White</ScribbleColor>
</ApplicationState>

When referring to elements in the tree, you must use the correct application state path notation, described below.

In addition to getting and setting state values, the PureWeb SDK provides an option to determine when a portion of application state has changed. Both the client and service SDKs allow developers to register state changed handler functions that are called when a single value or an entire section of application state changes.

Path Notation

The information in application state is stored as a hierarchical XML-like tree.

  To prevent conflicts, we strongly recommend that you do not write to the <PureWeb> element or its children: this section of application state is used internally by the PureWeb SDK to store bookkeeping and other such information.

When referring to a value in the tree, use the following path notation (note that the root <ApplicationState> element is not included):

/PureWeb/InteractiveQuality
/ScribbleColor

 

When naming the elements stored in the application state tree, follow the usual naming conventions for XML elements. For example, the first character in the name can be a letter or underscore but not a number, and names must not contain spaces or other punctuation characters.

For more information, see: http://www.w3.org/TR/REC-xml/#NT-NameStartChar

Initializing Application State

Application state must be initialized before a PureWeb application can start reading from and writing to it.

This initialization needs to occur when the service application is started. Typically, the code should be placed early on in the initialization of the service.

  If you already completed the task of connecting the service to the server, then you most likely already wrote the code necessary for this.

To initialize application state, create new StateManager and StateManagerServer objects in the service application.

C++

server = new CSI::PureWeb::Server::StateManagerServer();
stateManager = new CSI::PureWeb::Server::StateManager("Scribble");
server->Start(stateManager.get());

.Net

stateManager = new PureWeb.Server.StateManager("ScribbleApp", Dispatcher.CurrentDispatcher);
StateManagerServer server = new StateManagerServer();
server.Start(StateManager);

Java

stateManager = new StateManager("ScribbleApp");
StateManagerServer server = new StateManagerServer();
server.start(stateManager);

The StateManager object fires an event when it has been successfully initialized. A handler can be chained to this event, so that the application can perform actions, for example load initial values for some properties, when this occurs.

Creating State Initialization Handlers

The StateManager object fires an event when it has been successfully initialized. A handler should be attached to this event, and no changes should be made to application state until it has fired. The handler can be used to perform actions such as loading initial values for some properties.

Handlers can be on either the service or the client application. They can include any command that interacts with application state, such as read or write operations.

Here’s an example of adding a user-defined handler called ModifyMyAppState in a C# service application.

StateManager.Initialized += new EventHandler(ModifyMyAppState);

Client applications can listen for the event which is fired when the application state is initialized.

HTML5

pureweb.client.listen(pureweb.getClient(), pureweb.client.Framework.EventType.IS_STATE_INITIALIZED, function(){
    //Things to do once state has been initialized
});

iOS

To be notified when application state has properly initialized you should use the <PWFrameworkDelegate> protocol:

AppDelegate : NSObject <PWFrameworkDelegate>

Then, implement stateInitialized:

- (void)stateInitialized
{
    NSLog(@"Application State was initialized! It is now safe to interact with App State");
}

Alternatively, to allow a client application to interact with application state when it did not listen for the state initialization event, query for the isStateInitialized status:

HTML5

if (pureweb.client.framework.isStateInitialized()){
    //Interact with state
}

iOS

if ([PWFramework sharedInstance].isStateInitialized) {
    NSLog(@"Application State was initialized! It is now safe to interact with App State");
}

Writing to Application State

You use write operations to add new properties to application state, to provide initial values to these properties, and to change the values whenever needed.

You can write values directly to application state as shown below, or through the use of state changed handlers, described further on this page.

The examples below are taken from the Scribble sample application and show how to write to application state the value for the pen color (this is a user-defined property which the developer chose to call ScribbleColor).

HTML5

pureweb.getFramework().getState().setValue('ScribbleColor', 'red');

iOS

[[PWFramework sharedInstance].state setAppStatePathWithValue:@"/ScribbleColor" value:text];

Although the examples above illustrate how to do this on the client, it is also possible to write to application state on the service side, as illustrated by the Java code snippet below.

In this case, the framework object is just an instance of Framework.

framework.getState().setValue("/ScribbleColor", “red”);

Reading from Application State

Reading from application state is very similar as writing to it, with the exception that you only provide the path, and not the value.

HTML5

selectColor(pureweb.getFramework().getState().getValue('ScribbleColor'));			

iOS

PWXmlElement *colorNode = [[PWFramework sharedInstance].state.stateManager getTree::@"/ScribbleColor"];
NSLog(@"ScribbleColor is %@", [colorNode getText]);			

Although the examples above illustrate how to do this on the client, it is also possible to read from application state on the service side, as illustrated by the Java code snippet below.

In this case, the framework object is just an instance of Framework.

framework.getState().getValue("/ScribbleColor");

Registering State Changed Handlers

Registering state changed handlers allows developers to respond (read, write, edit, delete) when a change occurs in a particular path within application state.

These handlers come in two varieties: value changed handlers and child changed handlers.

Value Changed Handlers

Value changed handlers are triggered only when a specific value changes (they won't fire if the value hasn't actually changed). They can be added to any path in the application state tree. If the value at that path changes, the associated handling function will be called.

Typically, value changed handlers are defined inside the application state initialization function.

C++

CScribbleApp::StateManager().XmlStateManager().AddValueChangedHandler("ScribbleColor", Bind(this, &CScribbleView::OnScribbleColorChanged));

.Net

Program.StateManager.XmlStateManager.AddValueChangedHandler("ScribbleColor", OnScribbleColorChanged);

(...)

private void OnScribbleColorChanged(object Sender, ValueChangedEventArgs args)
{
    Color newColor = Color.FromName(args.NewValue);
}				

Java

stateManager.getXmlStateManager().addValueChangedHandler("ScribbleColor",onScribbleColorChanged);

In the examples above, when the value at /ScribbleColor changes, the service application will execute OnScribbleColorChanged.

The function that handles a state change event (in this case OnScribbleColorChanged), provides a ValueChangedEventArgs argument. This argument contains information about the change that triggered the event, including the path at which the change occurred and the new value.

You can also unregister these handlers using removeValueChangedHandler and removeAllValueChangedHandlers. The latter method removes all the value changed handlers from a specific path.

Child Changed Handlers

Child changed handlers work the same way as value changed handlers, except that they are triggered if any changes occur at or below the specified path in the XML tree.

Child changed handlers are not called when added; best practice is to query existing application state at the time a handler is added to see if the callback action is required. Adding nested child changed handlers is not recommended, as the order for which parent/child callbacks are called is not guaranteed. Callbacks are typically fired in the order that they are added, but this also not guaranteed. If your application requires consistency between multiple handlers, reconsider your application state structure.

Advanced Application State Methods

The SDK supports a variety of methods to accomplish more complex application state reading and writing tasks.

getValueAs

This method allows developers to retrieve parsed values from the application state; a data type must be specified. Refer to the APIs reference material for more information on this method.

setTree and getTree

These methods allow developers to get or set a section of application state. They take and return XML elements which can be read from or inserted into the path specified in the arguments.

The objects that store XML trees are platform-specific, represented in the native XML data type for that language, for instance XElement (C#) or Element (Java). Refer to the API reference material to find out the exact object type used.

The only client API to deviate from this model is HTML5. In this API, setTree and getTree take and return a JSON object, because this is a more intuitive format for storing complex data in JavaScript. However, the API does provide getTreeAsXml and setTreeAsXml if XML is the desired format.

StateLock

In multi-client environments, the application state should not be assumed to be perfectly synchronized, due to network latency or other factors. For this reason, it is possible to request a lock on the StateManager, which ensures that no changes to the application state take place while the lock is held.

Below is an example of how to acquire a state lock in Objective-C. Once acquired, the stateLock provides an API similar to StateManager:

PWXmlStateLock *stateLock = [_stateManager acquireLock];

Linking UI Elements to Application State

Application state can be used to link native user interface elements such as buttons and drop-down boxes to the service-side application logic.

For example, in the Scribble sample application, the pen color is stored in application state and when the end user interacts with an interface element to change the pen color, the value for this property gets updated in the application state tree.

The examples below illustrate how client-side native interface elements can use application state to control the behavior of an application.

HTML5

The example below is taken from the Scribble sample application. It illustrates how the native HTML5 <select> element is used to create a drop-down box for the pen color (lines 7 - 12). When the user changes the value in this box, the changeScribbleColor function is called (line 7). This function (line 2) simply gets the value of the selected option and sets it in the application state path ‘ScribbleColor’ (line 3).

<script type=’text/javascript’>
    function changeScribbleColor(e){
	    pureweb.getFramework().getState().setValue('ScribbleColor', document.getElementById('color').value);
	}
</script>

<select onChange="changeScribbleColor();" id="color">
    <option value="White">White</option>
	<option value="Red">Red</option>
	<option value="Blue">Blue</option>
	<option value="Green">Green</option>
</select>			

To extend this example even further, it would be possible to store the list of possible pen colors in application state, and when this list changes in the application state, the options in the select box could be dynamically adjusted accordingly.

iOS

This example shows a button labeled Set Counter to Five which, when clicked, triggers the setAppStateToFive function. This function then uses application state's setValue method to change the value of an element to 5.

- (void) viewDidLoad
{
    UIButton *exampleButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
	exampleButton.frame = CGRectMake(100, 100, 300, 30);
	exampleButton.titleLabel.text = @"Set Counter to Five";

	[exampleButton addTarget:self action:@selector(setAppStatetoFive) forControlEvents:UIControlEventTouchUpInside];

	[self.view addSubview:exampleButton];
}

- (void) setAppStateToFive
{
    [[PWFramework sharedInstance].state.stateManager setValue:@"TheValueFive" value:@"5"];
}

Flex

In the Flex version of the Scribble sample application, a text box is used for changing the pen color:

<mx:VBox width="100%" height="100%">
    <mx:HBox width="100%">
	    <mx:Label text="Color:" />
		<mx:TextInput id="colorTxtInp" width="200"
		    enter="viewModel.updateColor(colorTxtInp.text)"focusOut="viewModel.updateColor(colorTxtInp.text)" text="@{viewModel.color}" />				

When the end user enters a color in this text box, the input event calls the onScribbleColorChanged function, which gets the color value. The updateColor function then sets this color value in the application state path/ScribbleColor.

framework.state.stateManager.addValueChangedHandler("/ScribbleColor", onScribbleColorChanged);

public function onScribbleColorChanged(e:XmlChangeEvent):void
{
    color = framework.state.stateManager.getValue("/ScribbleColor");
}

public function updateColor(color:String):void
{
    framework.state.stateManager.setValue("/ScribbleColor", color);
}