API Reference | developer.brewmp.com API Reference | developer.brewmp.com

Developer

API Reference

AEECLSID_SETTINGSREG

Brew Release
Brew MP 1.0.2
See Also
AEEISettings.h AEEISettingsStoreFactory.h AEESettingsIniFactory.bid AEESettingsHeapFactory.bid AEEFileSystem2.bid
Description
SettingsReg is an implementation of ISettings that provides a unified settings namespace (registry) defined by URIs. The SettingsReg class itself does not provide any nodes within this registry; rather it is a top-level collector of other ISettings implementations that register themselves with SettingsReg via the .mif file, where each implementation "owns" one or more nodes within the namespace. SettingsReg combines the various implementations to form a single global registry (herein referred to as the "Registry") that is accessible by any component via the ISettings interface (subject to access privileges).
For example, two components, fooA and fooB, register the following namespaces with SettingsReg via their .mifs, respectively:
      "/apps/fooA/settings/"
      "/apps/fooB/settings/"

SettingsReg creates a virtual tree that represents these as follows:
      "/"
       |
       +---> "apps/"
                |
                +---> "fooA/"
                |        |
                |        +---> "settings/"
                |
                +---> "fooB/"
                         |
                         +---> "settings/"

Assuming fooB has allowed fooA to access its settings, fooA can use the ISettings interface to access any settings that fall under fooB's settings namespace, e.g. "/apps/fooB/settings/name".
URIs: URIs that identify particular settings subtrees that SettingsReg provides access to adhere to the following format:
   subtree        = "/" path
   path           = interiorNode "/"
   interiorNode   = nodeName [ "/" interiorNode]
   nodeName       = 

A couple examples of valid URIs that identify settings subtrees include:
"/myapp/mail/accounts/Home/imap/" identifies the settings subtree that stores information about the "Home" mail account's IMAP server. Applications might register for change notifications on this node if they need to know if the user changes server settings, for example.
"/~0xdeadbeef/" identifies the root of a settings subtree that uses a class id as the name.
URIs that identify specific settings follow this syntax:
   setting        = "/" path
   path           = [ interiorNode "/" ] nodeName
   interiorNode   = nodeName [ "/" interiorNode ]
   nodeName       = 

Examples of valid URIs that identify specific settings include:
"/myapp/profile" identifies the "profile" setting.
"/myapp/mail/accounts/Home/imap/server" identifies the IMAP server the "myApp" application connects to when checking mail for the "Home" mail account.
Namespace types: There are two types of ISettings implementations the SettingsReg class uses, native and non-native.
Native settings have the following attributes: - Use pre-defined ISettings settings implementations (no code to write)
- Are managed by a singleton service
- May use settings ACLs to control access
- May be listened to for changes

Non-native settings have the following attributes: - Require a custom ISettings implementation to be written
- Must define and enforce their own privilege model
- May or may not be listened to for changes (depends on implementation)

For all ISettings operations on the SettingsReg class, the URI of the setting is examined. If it falls within a namespace owned by a non-native implementation, the operation is delegated to that implementation. Otherwise the operation is delegated to the singleton service for handling by a native implementation.
Native settings: Native settings refer to settings that use a pre-defined ISettings implementation. SettingsReg has two pre-defined implementations:
1. .ini file-based This is an ISettings implementation that manages settings that reside in a .ini file. Since it is file-based, these settings are persistent across power cycles.
2. heap-based This is an ISettings implementation that manages settings that reside in heap. As such, these settings are not persistent across power cycles.
Components that wish to register native settings with the Registry need only identify which type of pre-defined ISettings implementation they wish to use along with any necessary data, e.g. the path to a .ini file to use. See AEESettingsIniFactory.bid and AEESettingsHeapFactory.bid for details on how to register for these types of native settings.
When a component has registered a native setting, it is referred to as a "store". There may be numerous stores in the system, each owning various parts of the Registry, and each may use a different type of technology to manage its data. For example, fooA in the example above may be a .ini file- based store and fooB may be a heap-based store.
The types of stores that are available for native settings may be extended dynamically. Stores are created using the ISettingsStoreFactory API. When a component chooses to use a .ini file-based store, the ISettingsStoreFactory API is used on a class that implements ISettings around a .ini file. So another type of store may be added to the system simply by implementing ISettingsStoreFactory. For example, if there exists an ISettingsStoreFactory implementation that creates an ISettings implementation which uses a database file to manage its settings (i.e. a .db-based store), components may register their .db-based settings with the Registry by simply specifying that ISettingsStoreFactory implementation and providing a corresponding .db file. See "Adding and using a pre-defined ISettings implementation for NativeSettings" below for more information.
The most important aspect of native settings is that they are managed by a singleton service. When an operation is performed on a native setting via SettingsReg, that operation is delegated to the NativeSettings service, which in turn delegates the operation to the particular store instance that manages that setting. Therefore all operations, such as reading/writing data, occur in the security context of the service, not in the context of the component that originated the operation.
The following diagram shows the relationship between native namespace owners.
   -------------               -------------
  |    fooA     |             |    fooB     |
   ------+------               ------+------
         |                           |
    [ISettings]                 [ISettings]       <---- implemented by AEECLSID_SettingsReg
         |                           |
   ------+---------------------------+------
  |                                         |
  |          NativeSettings Service         |
  |                                         |
   ------+---------------------------+------
         |                           |
    [ISettings]                 [ISettings]       <---- implementation from ISettingsStoreFactory_Create
         |                           |
  -------+--------           --------+-------
 |     fooA's     |         |      fooB's    |
 | Settings Store |         | Settings Store |
  ----------------           ----------------
         |                           |
  -------+--------           --------+-------
 |     fooA's     |         |      fooB's    |
 | Settings Data  |         | Settings Data  |
  ----------------           ----------------

Components that register native settings may also define special privileges that limit access to their settings by other components. In the diagram above, fooA may allow fooB access, but fooB may deny fooA access. The NativeSettings service manages these privileges. See "NativeSettings Privileges" below for more information.
This service also manages global notifications of native settings changes (since it knows about all accesses that occur). This allows multiple entities in the system, in potentially different contexts, to be notified whenever a setting or settings subtree changes. See "OnChange handling" below for more information.
Non-native namespaces: A non-native namespace is a custom ISettings implementation that registers for a particular namespace within the Registry. For example, AEECLSID_Foo implements ISettings and supports a single setting:
      mySetting=someValue

AEECLSID_Foo may install itself into the Registry at namespace "/foo", and its setting would therefore be accessible using the URI "/foo/mySetting". See "Adding and using a non-native ISettings implementation" below for more information.
Note that AEECLSID_Foo is responsible for documenting and implementing its own privilege checking, if required.
Namespace overlap: Native settings may be overridden by non-native settings. If more than one owner class of the same type (native and native, non-native and non-native) is registered for the exact same namespace, the behavior is undefined.
Consider the following overlap scenario:
   Native settings registered at "/users/"
   Non-native settings A registered at "/users/bob"
   Non-native settings B registered at "/users/bob/apps"
   
   This yields a tree of:
   
      "/"
       |
       +---> "users/"                  <--- implemented by native settings store
                |
                +---> "bob/"           <--- implemented by non-native settings A
                |       |
                |       +---> "apps/"  <--- implemented by non-native settings B
                |
                +---> "jim/"           <--- present in Native settings store
                |
                +---> "bob/"           <--- present in Native settings store
                |       |
                |       +---> "pets/"  <--- present in Native settings store

In this scenario, the two non-native settings are effectively overriding the "/users/bob/" settings present in the native store.
When overlap such as this occurs, the behavior for the various ISettings operations on the Registry are as follows:
Get/Set/OnChange: The operation goes to the deepest non-native settings that owns the key being operated on. For example, an operation on "/users/bob/apps/foo" would go to non-native settings B. If the non-native implementation returns AEE_EBADITEM (indicating it does not support the requested key) the operation will be provided to the native store. Any other return value will be returned to the caller, and no operation will occur on the native store.
Delete: The operation goes to the deepest non-native settings that owns the key being operated on as well as the native store. The return value from the non-native implementation is returned to the caller.
Reset: The operation goes to all registered namespaces that support the requested key. For example, calling ISettings_Reset on "/users/bob/" would perform a reset operation on both non-native settings A and B as well as the native store. If the native store returns AEE_EBADITEM (indicated it does not support the requested key), then the value returned to the caller will depend on the non-native settings - if any of the non-native settings returns AEE_SUCCESS, the operation is deemed successful and AEE_SUCCESS is returned to the caller, otherwise an error code is returned. If the native store returns anything other than AEE_EBADITEM, that error code is returned.
GetNumChildren/GetChildName: Enumeration operations will take into account overlap, so enumerating over "/users/" will return 2 children named "bob/" and "jim/". Likewise, enumeration over "/users/bob/" will return 2 children, "apps/" and "pets/". If non-native settings A had more settings under "/users/bob/", those would also be enumerated.
NativeSettings Privileges: NativeSettings controls all access to native namespaces system-wide. The calling module must have been granted the proper privileges to access settings. Modules must have read access to a particular setting namespace to retrieve settings from it, while write access is required to modify, add, remove, or reset settings within a settings namespace.
NativeSettings uses an ACL-based privilege model. Any node within a namespace can be protected with read and write privileges defined by the module. By default, the owner of the namespace is granted read/write privileges to the entire namespace.
Note that a caller with AEEPRIVID_NativeSettingsR or AEEPRIVID_NativeSettingsRW privileges will be granted the appropriate access to the namespace (read and read/write, respectively) regardless of any ACLs defined for the namespace.
The format of the NativeSettings ACLs is identical to the FS ACL format described in AEEFileSystem2.bid. Note that only the format of the ACLs is the same as file system ACLs; other than that, settings ACLs have nothing to do with file system ACLs.
Note: An ACL for a setting or settings subtree that does not fall under the owner's namespace is ignored.
Root node privilege: The privilege for the root node ("/") is
"0x00000000 = r / :/"
This allows everyone to iterate over the root settings node but nothing else. The children under the root node (the various settings namespaces) will define the appropriate privileges for each namespace.
OnChange handling: All ISettings methods implemented by NativeSettings are handled as follows:
1. Use the key provided to identify which store owns the setting 2. Perform the operation on the store using an adjusted key
Normally the result from the operation on the store is returned to the caller, but there is one exception: OnChange().
When NativeSettings delegates a call to ISettings_OnChange() to a store, it examines the return code. If the store does not implement OnChange() (returns AEE_EUNSUPPORTED) NativeSettings will still honor the OnChange() request and handle it internally, so any _Set(), _Delete(), or _Reset() operation will still cause the change notification to occur. Any return code other than AEE_EUNSUPPORTED is passed back to the caller.
The implication of this is that a store does not necessarily need to support OnChange() - NativeSettings will handle it. But if a store's settings can change outside of calls to ISettings, the store should implement OnChange().
Releasing stores: NativeSettings may release its stores under certain conditions, e.g. low memory. However, NativeSettings will not release stores that meet the following two criteria:
1. The store implements OnChange() 2. There are one or more active notifications on the store (i.e. notifications created with OnChange() have not yet been cancelled)
Reprovisioning: ISettings_Reset() may be used to reset a particular setting or settings subtree within a settings namespace. Modules that have access to write settings to a namespace may completely reset it, restoring it to its default state. Some namespaces may not support the Reset operation and attempts to do so will generate errors.
Adding and using a pre-defined ISettings implementation for NativeSettings: To create a .ini file- or heap-based store, see AEESettingsIniFactory.bid and AEESettingsHeapFactory.bid, respectively, for details. To create a new pre-defined ISettings implementation that components may use for native settings, do the following:
1. Implement the ISettingsStoreFactory API (see AEEISettingsStoreFactory.h) that implements the new type of store.
2. Include the SettingsCIFHelpers helper script and the factory .bid file in the .cif of the component that wishes to use the new type of store:
      include "AEESomeStoreFactory.bid"
      local s = require 'SettingsCIFHelpers'

3. Register the namespace with SettingsReg using RegisterCustomStore{}. This may include optional parameters to pass to the factory as well as settings ACLs to allow other modules access to your namespace.
      -- my settings will be located under "/myApp/settings/..."
      s:RegisterCustomStore {
         owner = 0xdeadbeef,
         key = "/myApp/settings",
         store = AEECLSID_SomeStoreFactory,
         args = { key = "value" }    -- optional key/value pairs to pass to the factory
         acls = {                    -- optional ACLs to limit access
         {
            -- grant everyone read access to my settings but write access to
            -- only those modules belonging to the 0xdeadd00d group
            {
               groups = {0}, 
               perms = "r/r",
            },
            {
               groups = {0xdeadd00d}, 
               perms = "rw/rw",
            },
            path = "/myApp/settings"
         }
      }

"owner" is the class id of the component that owns this namespace. The owner class id is used to create an implicit R/W ACL for the namespace and is required. Note that the owner class id must be a valid class in the system. Using an invalid class id will result in the registration being ignored.
"key" is the full settings path that indicates the root of the namespace. The settings will be located under this root. In the example above, the settings are accessed under the "/myApp/settings/" subtree. Valid keys adhere to the following format:
         namespace      = "/" path
         path           = interiorNode "/"
         interiorNode   = nodeName [ "/" interiorNode]
         nodeName       = 

"store" is the class id of the implementation of ISettingsStoreFactory that will be used to create the ISettings implementation to manage the settings.
"args" is a table of any extra information (name/value pairs) that the factory may require to create/manage the store.
"acls" is a table of NativeSettings ACLs. For more information about the ACL format, see AEEFileSystem2.bid.
All parameters passed to RegisterCustomStore{} will be built into a string and provided to the call to ISettingsStoreFactory_Create().
Adding and using a non-native ISettings implementation:
1. Implement the ISettings API.
2. Include the SettingsCIFHelpers helper script and the .bid file in the implementation's .cif:
      include "MyCustomSettings.bid"
      local s = require 'SettingsCIFHelpers'

3. Register the class id for a particular namespace
   -- my settings will be located under "/myCustomSettings/..."
   s:RegisterClass {
      class = AEECLSID_MyCustomSettings,
      key = "/myCustomSettings"
   }

"class" is the class id of the component that owns this namespace. This is the class that implements ISettings.
"key" is the full settings path that indicates the root of the namespace. The settings will be located under this root. In the example above, the settings are accessed under the "/myCustomSettings" subtree. Valid keys adhere to the following format:
         namespace      = "/" path
         path           = interiorNode "/"
         interiorNode   = nodeName [ "/" interiorNode]
         nodeName       = 
Default Interface Name