Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • authenticated user owns the preference, or
  • authenticated user belongs to a group that is visible to the visibilityList

Preference Store

We will have a PreferenceStore interface rather like DurableConfigurationStoresimiliar to the DurableConfigurationStore but with some notable difference

  • open/close

  • upgrade
  • visit
  • create
  • update
  • delete

Compared to the DurableConfigurationStore the PreferenceStore has the following differences:

  • no upgrade method. The store should handle upgrades transparently during startup/open. This is considered a fault in the original API
  • no visit method. Rather the open method should handle initial loading of the data. See below for more detail.

API is in terms of PreferencesRecord PreferenceRecords (analogous to ConfiguredObjectRecords) .  The stores themselves will hold the preference records as JSON, but this isn't part of the contract.which have minimal knowledge of the internal structure except from the UUID. The ID is necessary to identify records for deletion and update operations.

Broker and VirtualHost have AbstractSystemConfig and AbstractVirtualHostNode have a separate preference stores.

  • The Broker and VirtualHost configuration will have an attribute of a custom ManagedAttributeValueType containing a type and an optional attributes filed for type specific configuration (e.g., store location).
  • The concrete instances of SystemConfig and VirtualHostNode responsible for creating concrete instances of SystemConfig and VirtualHostNode responsible for creating the preference store too.
  • For storage mechanism BDB, JDBC, Derby there would be a restriction that the preference store must be co-located with the configuration.
  • For storage mechanism JSON the preferences would be stored in a separate file.

Recovery

At recovery time the AbstractSystemConfig and AbstractVirtualHostNode will need to read all the preferences from their respective stores and create Preference objects.    This needs to occur after the configured objects are recovered. In this phase, objects corresponding to the records must be created.  The recovery algorithm will be similar to that of configured object recovery as preferences may reference other preferences, so some preferences (Dashboards) may have to await the creation of others before they may be created.   As preferences are created they need to be assigned to their associated configured object.

If during the recovery phase, a preference is encountered that refers to a configured object that no longer exists, the preference can be dropped.  If a preference is found that refers to a preference that no longer exists, the reference can be removed.  The latter would happen if a dashboard of user B refers to a query of user A.  If user A deletes their query, user B's reference will be left dangling.  On next recovery, the dangling reference must be removed.  (The UI should probably just display a ? where the query would have been).

Persistence

Code Block
languagejava
interface PreferenceStore
{
    // see below for the Updater and Recoverer interfaces
    Collection<PreferenceRecords> openAndLoad(PreferenceStoreUpdater updater);

    // safely persist all state and close all resources
    void close();

    // adds preferences to the store
    void create(Collection<PreferenceRecord> preferences);

    // updates existing preferences. throws an exception if preference with given id is not already in the store
    void update(Collection<PreferenceRecord> preferences);

    // updates existing preferences. if a preference with given id is not already in the store it will be added
    void updateOrCreate(Collection<PreferenceRecord> preferences);

    // remove preferences from the store. throws an exception if preference with given id is not already in the store
    void delete(Collection<PreferenceRecord> preferences);
}

interface PreferenceRecord
{
    UUID getId();
	Map<String, Object> getAttributes();
}

Recovery

At recovery time the PreferenceRecords in the PreferenceStore will need to be converted into Preference objects. This needs to occur after the configured objects are recovered. In this phase, objects corresponding to the records must be created. The recovery algorithm will be similar to that of configured object recovery as preferences may reference other preferences, so some preferences (Dashboards) may have to await the creation of others before they may be created. As preferences are created they need to be assigned to their associated configured object.

If during the recovery phase, a preference is encountered that refers to a configured object that no longer exists, the preference can be dropped.  If a preference is found that refers to a preference that no longer exists, the reference can be removed.  The latter would happen if a dashboard of user B refers to a query of user A.  If user A deletes their query, user B's reference will be left dangling.  On next recovery, the dangling reference must be removed.  (The UI should probably just display a ? where the query would have been).

The idea behind getting rid of the visit method is to be able to use a store that is essentially write-only after it has been read from disk. However the loading needs some customization hooks:

  • we want to ability to update individual preferences. This may include updating, creating and deleting preferences. This might require multiple passes.
  • Since the update step might arbitrarily modify the preferences the store needs to be informed about the changes so that the update can be persisted.
  • preferences need to ability to reference each other. This is done by storing UUIDs. The objects using the preferences are responsible for resolving those references.

The first to points are the responsibility of the PreferenceStoreUpdater while the second should be performed by the PreferenceStoreRecoverer.

The recoverer is responsible for

  1. Convert PreferenceRecord to Preference
  2. Convert generic attributes to a type specific PreferenceValue
  3. Attach Preference to AbstractConfiguredObject
Code Block
languagejava
interface PreferenceStoreUpdater
{
    Collection<PreferenceRecord> updatePreferences(String currentVersion, Collection<PreferenceRecord> preferences);
    String getLatestVersion();
}

Persistence

Preferences are considered immutable. All changes to preferences should go through a UserPreferences facade which is responsible for updating the storeThe persistent stores need to listen for new preferences, updates to existing preferences or deletes.  A listener mechanism similar to ConfigurationChangeListener will be used.

High Level Class Diagram

...