The Information Service is a database storing information objects. An object is an entity with a name and a value. The service provides functions for getting and setting the value of objects as well as subscribing to changes in object values.
The information objects managed by the Information Service are organized in a storage structure. The Information Service handles the information sources in the storage structure by applying an adapter to each source. Different adapters are responsible for gathering objects from different places, e.g., there is an adapter responsible for gathering objects via infocast and there is an adapter responsible for gathering objects from the flash memory.
The adapters are divided in editable and non-editable adapters. The editable adapters allow some or all of their objects to be changed by the user, either permanently (the values are restored after reboot or standby) or volatile (the values are lost at reboot and standby).
Note! In the sections below sometimes the expression "get/set object" is used when actually "get/set the value of an object" is intended. All to make the text easier to read.
When you set an object in the Information Service you have to specify whether the object should be edited in a permanent way or in a volatile way. If you want a value to survive reboot and standby you should store it permanently otherwise volatile.
Observe the adapter behavior described in the Adapters section. If you set a value permanently or volatile (in a permanent or volatile adapter) the value reflected by the Information Service interface will not change if there is a higher priority adapter containing the object. For instance, consider an Information Service configuration with three adapters:
If Adapter N contains the value "N" for the object "config.object" and we set the value "P" permanently, no subscribers will be notified about an update and if someone tries to get the object they will get the value "N".
However if we set the value "V" volatilely, subscribers to "config.object" will be notified and the value "V" will be returned when someone gets the object. This is because the value will be stored in Adapter V which has higher priority than Adapter N that already contains a value for the object.
When an object is unset, all values in all permanent or volatile adapters are removed.
It is possible to configure the Information Service in such a way that not all objects may be changed. In that case the objects that may be changed are specified in a white list and if you try to edit any other than these objects an TToiPermissionDeniedException is raised.
Subscriptions are used to subscribe to changes of values of objects. Subscriptions are done using observer registration (C++) or event listener registration (JavaScript).
It is possible to subscribe to objects that does not yet exist in the Information Service. In that case the service requests the object from all its adapters to try to force them to get the object (some adapters, like the infocast adapter, does not get all objects but rather waits for a request for some of the objects, to avoid bloating the memory space with unnecessary data). When the object becomes available a callback is made to the subscriber.
The Information Service makes callbacks to the subscriber when objects change or are removed (OnObjectsChanged and OnObjectsRemoved respectively). The callbacks contains names of the objects, the subscriber has to explicitly call the Information Service to get the new values when an update occurs.
When a subscriber first registers itself as an observer on some objects an immediate callback is made with the objects that the service knows about (objects that exist in some adapter).
The expressions used to subscribe to objects does not have to be actual object names. It is possible to use a wildcard to subscribe to several objects at once (observe that object expressions are not so called regular expression).
The expressions can contain a wildcard, "*". It must be used at the end of the expression, immediately following a "." (dot) otherwise it is not treated as a wildcard, but rather as an ordinary character in the name of the object. The wildcard matches any (none, one or several) characters.
The following table illustrates what expressions uses the "*" character as a wildcard and which use it as an ordinary character:
Object expression | Contains wildcard? |
---|---|
config.* | yes |
config* | no |
config.ip* | no |
The following table illustrates which objects are covered by a wildcard expression:
Object expression | Object name | Match? |
---|---|---|
config.* | config.ipaddress | yes |
config.* | config.a.b | yes |
config.* | configaaa.a | no |
config.* | a.b | no |
config.a.* | config.a | no |
If a subscriber subscribes to a wildcard expression and an "overlapping" object (e.g., config.* and config.ipaddress) the subscriber still only gets one call for each update of the object (config.ipaddress).
It is recommended that subscribers unsubscribe objects that they are no longer interested in as soon as possible. This enables the adapters to manage their resource utilization in a better way.
When a subscriber unsubscribes objects with a wildcard, only the specific expression is unsubscribed, e.g., if you are subscribing to config.* and config.ipaddress, and then unsubscribe config.*, you will still be a subscriber to the config.ipaddress object.
Sometimes it is important to get transaction-like behavior, i.e., you want to be able to get or set a collection of objects in one atomic operation. In the Information Service this is solved with functions that gets or sets several objects at once (GetObjects() and SetObjects()). This is a somewhat crude solution since it does not provide any rollback functionality but is good enough for most purposes.
The subscription functionality also tries to tell observers about all objects that have changed by an operation in the Information Service in one call to OnObjectsChanged. There is one catch, all objects must change in the same adapter for this to be true, otherwise several calls to OnObjectsChanged() are used.
Objects can change because some user calls the Information Service to set or unset objects or because of an outside event, e.g., an object is updated via infocast.
Observe that different functions are called for objects that change and objects that are removed from the service (OnObjectsChanged() and OnObjectsRemoved()).
See also: TOI Information Service Interface