Mergeable XML

Overview

Cloud Softphone and all apps based on Acrobits SDK allows various configurations to be provisioned from the server. At the same time, the apps often contain “settings” or “preferences” GUI which lets the end user set various configuration options.

In such a situation, collisions are possible. In case the values from settings GUI and from provisioing are simply saved, values entered by end user will be overwritten by provisioning and vice versa, which leads to chaos and bad user experience.

To overcome this, we created a simple system of merging the values based on priorities, which may be either set explicitly, or be deduced automatically from where the values came from.

Data Model

As the name suggests, Mergeable XML works with XML documents. These documents are treated as key-value stores, where names of nodes which are children of the root nodes are the keys and content of these nodes are values. The node values may be strings - text data inside the nodes, or xml sub-trees, in which case, the whole sub-tree is taken as a single value.

Important

Mergeable XML document can be seen as a list of key-value pairs, where keys are strings and values may be either strings, or XML sub-trees.

Example:

<account>
   <host priority="10" source="provisioning">example.com</host>
   <transport priority="20" source="extProv">udp</transport>

   <rewriting priority="40" source="gui">
      <rule>
         <conditions>
            <condition type="doesntStartWith" param="+"/>
         </conditions>
         <actions>
            <action type="prepend" param="+420"/>
         </actions>
      </rule>
   </rewriting>
</account>

This example defines a key-value store of three entries: host=>example.com, transport=>udp and rewriting=>(xml tree). This is an actual example of Account XML, which uses Mergeable XML model.

The XML nodes which are immediate children of root node will be called key nodes and the content of these nodes (either strings or XML sub-trees) will be called values.

Priorities

Every key node in Mergeable XML must have two attributes: priority and source.

source

The attribute source is a human readable name which explains where does the key node came from (for example default, gui etc.) and its value is not used for anything else than troubleshooting.

priority

This attribute contains an integer value in decimal notation. This value specifies the priority of this particular key-value entry, which determines whether this value is going to be overwritten or not.

Important

Existing key node is overwritten by an incoming key node ONLY if the priority of the incoming key node is same or higher than priority of the existing key node. In case the key-node IS overwritten, the incoming key node value and attributes replace the existing key node value and attributes.

Merging

In case the app stores some data as Mergeable XML, the values may never be written directly. The only way to modify this data is by merging-in other Mergeable XML. The process of merging decides whether the values should be written or not based on key node priorities.

Default Priorities

The incoming XML to be merged in may come from various sources: provisioning from Cloud Softphone portal, response of some provisioing web service or it may be created by the app GUI when the user saves the form. The attributes priority and source don’t need to be always explicitly defined; in case they are not set, the app will deduce them based on the origin of the data and assign a default priority:

source priority description
default 0 default value, hardcoded in the app
provisioning 10 values coming from Cloud Softphone portal
extProv 20 values coming from external provisioning web services
gui 40 values set by end users using GUI
system 100 values set by system which should never be overwritten

Note

Priorities of 100 and higher are reserved and should not be used. The app stores various persistent data using these priorities and accidentally overwriting them may cause undefined behavior.

Localized values

In case of string values, it is possible to specify them either as text contents of the XML node, like shown in the example above for transport or host, or as a xml tree with multiple <value>> nodes for different languages.

Example:

<dialAction id="recordedCall">

   <displayName priority="20" source="extProv">
      <value lang="cs">Nahrávaný hovor</value>
      <value lang="jp">記録されたコール</value>
      <value>Recorded Call</value>
   </displayName>

</dialAction>

The key node dialAction is a localizable node. The app will pick the string from <value> subnode which matches the current device locale. If such node is not found, the app will take the value from <value> subnode which does not contain a lang attribude - this node serves as a default. If such a node also doesn’t exist, the app uses the text contents of key node, just like in non-localized case.

Examples

Let’s assume the app has an account with values and priorities as in the previous example. The user opens “edit account” form and decides to change the transport to tcp. When saving the form, the app internally generates the following Mergeable XML:

<account>
   <transport priority="40" source="gui">tcp</username>
</account>

It will then try to merge this document with the one stored in the app. Since the incoming priority of 40 is higher than the stored priority of 20, the merge will be performed and the resulting document will look as follows:

<account>
   <host priority="10" source="provisioning">example.com</host>
   <transport priority="40" source="gui">tcp</transport>

   <rewriting priority="40" source="gui">
      <rule>
         <conditions>
            <condition type="doesntStartWith" param="+"/>
         </conditions>
         <actions>
            <action type="prepend" param="+420"/>
         </actions>
      </rule>
   </rewriting>
</account>

If later, the external provisioning web service is called again and it sends the key node transport in its response, the app will assign default priority of 20 to this node and attempt to merge it. This time, the value will not be written, because the existing priority of 40 is higher and the user-entered value stays.

In case the provider later decides to explicitly set the transport key node priority higher, it can return the following node in the external provisioning response:

<account>
   <transport priority="50" source="extProv">url</transport>
</account>

This time, the value will be merged, because the priority is higher than the stored 40. When the user opens “edit account” form now, he will see the transport field as read-only, because the GUI is intelligent and knows that any new value would get a default priority of 40 and would not beat the existing priority of 50.

Note

In case the value is XML tree, the value is taken as a whole. If the external provisionig web service sends a node <rewriting priority="50"> in its response, the whole content of the incoming node will be stored. The merging process is not recursive.

Filters

Some values coming from provider’s web services may not be merged even if the priority is set high enough. In case the incoming value would enable functionality which is not included among the selected Cloud Softphone features on Cloud Softphone portal, the relevant key node will be filtered out even before merging is attempted.