Wiki

Clone wiki

SAGE2 / SAGE2 Application API - Data Sharing

Communication between SAGE2 applications

All applications running on the display client can access each other through the global variable, applications. However, it is often not advisable to do this when multiple applications of the same type are running due to difficulties in selecting the correct one.

There are two options an application may take to establish communications between each other. Parent-child which enables direct communication, and a server variable pubsub system. The pubsub system has been tested more extensively with multiple display clients and so far seems to work without issues. The parent-child system enables direct communication, but users must be aware of the potential to break synchronization within environments using multiple display clients.

One part of the system that has been abstracted and made generic is the ability for applications to launch other applications.

Parent and child applications

Applications launching other applications

All applications have access to the following function:

// Function signature
launchAppWithValues: function(appName, paramObj, x, y, funcToPassParams) {
   ...
Calling this function will send a message to the server. The server will then attempt to launch the application with name appName. Typically this is the name of the folder which the application resides within. The effect is nearly identical to launching an application from the UI with the exception that additional data is passed during initialization and the launcher application will be updated after the child is launched with the correct app_id.

The parent is the application which calls launchAppWithValues while the child is the application that gets launched as result. A child can only have one parent, but a parent can have many children.

The child will be given the paramObj during initialization. The paramObj must be an object and has one reserved property, parent. The parent property is used to pass the child application its parent's appID. The application being launched will be positioned at coordinates x,y. The last parameter, funcToPassParams is optional. If used, it must be a string containing the name of a function that exists on the child. If specified, as part of the initialization the funciton name matching funcToPassParams will be called on the child and passed paramObj.

All functions described on this page are part of the SAGE2_App class unless otherwise specified and are invoked by this.functionName(). The following would be an example of how to launch the Google Maps application that is 100px to the right and below the parent

this.launchAppWithValues("googlemaps", {}, this.sage2_x + 100, this.sage2_y + 100);

Parent and child functionality

After an application launches another it becomes a parent while the launched application becomes the child. During initialization a couple of variables are updated to reflect this.

After the child application is launched the parent will be notified of its app_id. As part of the initialization, the child application will be given the parent's id as part of the paramObj. The parent id is automatically stored within the child during initialization.

During the init() function, the child will have access to the paramObj. This is accessible through data.customLaunchParams. The property parent will contain the parent id. It is not recommended to alter that property as the alteration will be stored as the parent id.

After the child has been init, it can access the parent id using this.parentIdOfThisApp. The parent can access the child's id with this.childrenAppIds, which is an array.

Once they have access to each other's id, it can be used in conjunction with the data sharing described in a later section Data Sharing.

Finer control of parent child communication

It is recommended to use the data sharing described in the next section to pass data between parents and children. Using the data sharing system has better control when there are multiple display clients. However some legacy functions that still exist are still available to send data between parents and children. The reason it is advised to not use this is that the functions transfer the data within the display client which they reside. The data doesn't pass through the server, so there is no guarantee that the other display clients see the result, even if programmatically they should have. With this you have been warned. The benefit to using the following is that a higher level of control is gained as direct manipulation is possible.

Children can pass data to parents using

this.sendDataToParentApp("nameOfFunction", data)
The nameOfFunction must be a string containing the name of a function that exists on the parent. Then data will be passed as the parameter.There are no data type restrictions placed up on data.

Parents can send data to children using

this.sendDataToChildrenApps("nameOfFunction", data)
Similarly, nameOfFunction must be a string containing the name of function, but it must exist within all child applications. That function will be passed data as the parameter.

There is no helper function allowing a parent to send directly to one child. Instead the following must be done:

applications[app_id]["nameOfFunction"](data);
This will activate function "nameOfFunction" on the application with id app_id and pass data as the parameter. In actuality applications[app_id] provides direct access to another application. Any variable or function can be accessed in this manner.

Parent access their children ids using this.childrenAppIds, which is an array. It starts empty by default. Getting the number of children is with this.childrenAppIds.length.

Children access their parent's ids with this.parentIdOfThisApp. Applications without parents, will have this value as null.

// Accessing application object references

// A parent accessing a child
var child = applications[this.childrenAppIds[0]]

// A child accessing a parent
var parent = applications[this.parentIdOfThisApp]

Data sharing

The shared variables are hosted on the server. The creation, modification, and retrieval of the variables works similar to a topic based publish-subscription system. A couple of things to keep in mind is that all applications have equal rights. Any application can: create, read, modify, or delete variables. It is however recommended that variables are not manually deleted. Instead mark the variable and let the application clean up handlers remove the variable from the server.

In addition to direct variable handling, applications may also subscribe to variable creation, a specific variable's update, or requesting a list of variables.

Using the data sharing system

Creating and modifying variables

Creation

An application can at any time, create variables using the following function:

// Function signature
serverDataSetValue: function(nameOfValue, value, description, shouldRemoveValueFromServerWhenAppCloses = false) {
   ...

Creation is actually built into the set value function. The first parameter, nameOfValue, specifies the name of the variable. If the specified name doesn't exist, the server creates one with the given name with the given value and description. The variable will not be created if value is undefined. However null is acceptable as a value.

If shouldRemoveValueFromServerWhenAppCloses is set to true, when the application is closed, as part of cleanup it will send a message to the server to remove the variable. Removal is an association made within the application. Since the function is available to any application, it is recommended that only the creator of the variable removes the variable. If the variable is removed, this doesn't prevent another application from creating a variable with the specified name again.

The serverDataSetValue function and all following functions (unless noted) are built into the application itself. To call this function within an application:

this.serverDataSetValue("helloVariable", "Hello World", "An example variable", true) {
The above line will set the variable called helloVariable to the value "Hello World" and on the server the description of the variable will be set to "An example variable". The fourth parameter was optional. Since it was given and true, when the application closes the helloVariable variable will be removed.

In cases where there are multiple display clients, only the master display will send a message to the server.

Modification

If a variable with nameOfValue already exists, the given value will replace the current value of the variable. The type of value doesn't have to match and there is no type enforcement. The type of data can change throughout the variables life time. In addition, due to right equality, another possibility is that two different applications continue to override the same variable name even if the values are not compatible.

After a value update, all subscribers of a variable will notified. More details on this in the subscription section.

Retrieving a variable's value

An application can request the value of variables using the following function:

// Function signature
serverDataGetValue: function(nameOfValue, callback) {
   ...

The server will check all variables for one that have been named, nameOfValue*. If there is none with that name, nothing will happen. If the variable does exist, the application will have its function named callback** called and given the value as the parameter. As mentioned in creation and modification, the datatype can change and is up to the developer to create a function to handle the data.

In environments with multiple display clients, only the master display will send out the get data message to the server. But, each display client will be sent the information and pass the data to the application through its callback function as the parameter.

Subscribing to variable updates

An application can subscribe to variables. Anytime the value is updated, all subscribing applications will be notified through their callback function.

// Function signature
serverDataSubscribeToValue: function(nameOfValue, callback, unsubscribe = false) {
   ...

For the above, nameOfValue is which variable the application wants to subscribe to. If the variable does not yet exist, the server will make a placeholder variable. When the variable has its value updated all subscribing applications will be notified through their callback function. The value will be passed to the function as a parameter. The third parameter to serverDataSubscribeToValue is optional with a default value of false. By passing true, this will unsubscribe the application from the variable. No change will occur if the application wasn't subscribed.

Helper functions

The serverDataSetValue function requires developers to choose variables ahead of time that will not collide with other variables. In addition, multiple instances of the same application may cause collision. The following helper functions are provided to automatically append the application's id in front of the variable name. This way if multiple instances of the application are open, they will write to separate variables instead of each writing to the same variable.

Two functions are provided to help with the common usage of broadcasting data and broadcasting a location to send data.

// Function signature
serverDataBroadcastSource: function(nameSuffix, value, description) {
   ...
}


serverDataBroadcastDestination: function(nameSuffix, value, description, callback) {
   ...
}

In serverDataBroadcastSource the intention is that the application has data for others. The first parameter is the suffix which to add to the variable name for creation. The final format will be app_id:source:nameSuffix. The given value and descrption will be used to initialize the variable. Like serverDataSetValue, the value undefined will not create a variable, but null is acceptable.

For serverDataBroadcastDestination the intention is that the application is broadcasting a destination which data can be sent. This is different from broadcasting a variable for other application. The application which calls this function not only creates the variable, but also subscribes to it. Any updates to the variable it will know about. In this way when other applications set the value, the creator will be notified of the changes. An initial value will still be needed. The name will be of the format app_id:destination:nameSuffix. All value updates to the variable will be received through callback as a parameter.

Since the serverDataBroadcastSource will alter the name of the variable, a helper function was created to assist with updating the variable by automatically formatting the variable name given the suffix.

// Function signature
serverDataSetSourceValue: function(nameSuffix, value) {

Given the nameSuffix, the function will automatically prefix to match the format app_id:source:nameSuffix. The given value will be used to update the variable.

Subscribing to variable creation

In addition to subscribing to a specific variable value update, applications can subscribe to new variable creation.

// Function signature
serverDataSubscribeToNewValueNotification: function(callback, unsubscribe = false) {
   ...
When a variable is created, all applications subscribing to new variable creation will be notified through their callback function. Upon new variable creation, subscribing applications' callback function will be called and passed the following object

dataForApp.data = {
    nameOfValue: "string containing name of the variable",
    description: "string describing the variable given by application",
    status: "add"
};

Removing variables from the server

It is recommended to let the closing application's cleanup functions handle variable removal by setting the flag in serverDataSetValue. But if you want to manually remove variables the following functions can be used

// Function signature
serverDataRemoveValue: function(namesOfValuesToRemove) {
   ...
}

serverDataRemoveAllValuesGivenToServer: function() {
   ...
}

Using serverDataRemoveValue will remove from the server the variable with name matching namesOfValuesToRemove. namesOfValuesToRemove can be a single string for an array of strings. If an array of strings is given, each variable with a name matching a string in the given array will be removed.

Otherwise, serverDataRemoveAllValuesGivenToServer will remove all variables from the server which the application has flagged for removal with serverDataRemoveValue. This function is automatically called by the application when it is closed.

Updated