...
API is in terms of Preferences (analogous to ConfiguredObjectRecords). The stores themselves will hold the preference records as JSON, but this isn't part of the contract.
Broker and VirtualHost have 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 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.
Code Block | ||
---|---|---|
| ||
interface PreferenceStore
{
void open(PreferenceStoreUpdateVisitor updateVisitor, PreferenceStoreOpenVisitor openVisitor, PreferenceStoreResolveVisitor resolveVisitor, PreferenceStoreAttachVisitor attachVisitor);
void close(PreferenceStoreCloseVisitor closeVisitor);
// adds preferences to the store
void create(Collection<Preference> preference);
// updates existing preferences. throws an exception if preference with given id is not already in the store
void update(Collection<Preference> preference);
// updates existing preferences. if a preference with given id is not already in the store it will be added
void updateOrCreate(Collection<Preference> preference);
// remove preferences from the store. throws an exception if preference with given id is not already in the store
void delete(Collection<Preference> preference);
} |
Loading of Preference Store
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.
- preferences need to ability to reference each other. One way to achieve this is that separate instantiation and dependency resolution.
Recovery
At recovery time the PreferenceStores' parents 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).
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 it might not be sensible or feasible to instantiate the type specific PreferenceValue. During this step the PreferenceValue is simply a GenericPreferenceValue (i.e., Map<String, Object>)
In the PreferenceStoreOpenVisitor should turn the GenericPreferenceValue into a type specific PreferenceValue - preferences need to ability to reference each other. One way to achieve this is that separate instantiation and dependency resolution.
Code Block | ||
---|---|---|
| ||
interface PreferenceStoreUpdateVisitor | ||
Code Block | ||
| ||
enum PreferenceStorePassType { UPDATE, OPEN, RESOLVE, CLOSE } interface MultipassVisitor { // Notifies the visitor that a new pass is commencing void beginPass(PreferenceStorePassType passType); // Notifies the visitor that a pass completed. // The store should treat a step as incomplete until endPass returns true. Only then should any changes be made persistent. // @return true to indicate that no further pass is necessary // @return false to indicate that another update pass should be performed boolean endPass(PreferenceStorePassType passType); } interface PreferenceStoreUpdateVisitor extends MultipassVisitor { // Notifies the visitor that a new pass is commencing void beginUpdatePass(); // Called for every preference currently in the store // The Preference p will be replaced with whatever the method returns. Let us consider three cases // a) the collection is empty: The preference is deleted // b) the collection contains a single preference with the same id as p: the preference is updated // c) the collection has multiple preferences: new preferences are created Collection<Preference> visitForUpdate(Preference p); } interface PreferenceStoreOpenVisitor extends MultipassVisitor { // CalledNotifies forthe everyvisitor preferencethat currentlya in the storepass completed. // The Preferencestore pshould willtreat bea replacedstep withas whateverincomplete theuntil methodendUpdatePass returns true. Only then should Preferenceany visitForOpen(Preference p); } interface PreferenceStoreResolveVisitor extends MultipassVisitor { changes be made persistent. // Called for every preference currently in the store@return true to indicate that no further pass is necessary // The@return Preferencefalse pto willindicate bethat replacedanother withupdate whateverpass theshould methodbe returns.performed Preferenceboolean visitForResolveendUpdatePass(Preference p); } interface PreferenceStoreCloseVisitor extends MultipassVisitorPreferenceStoreOpenVisitor { // Notifies Calledthe forvisitor everythat preferencea currentlynew inpass theis storecommencing // The store will write to disk whatever thisvoid beginOpenPass(); // Called for every preference currently in the store // The Preference p will be replaced with whatever the method returns. // This should turn the GenericPreferenceValue Preference visitForClose(Preference p); } |
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.
...
into a type-specific PreferenceValue
PreferenceValue visitForOpen(String type, Map<String, Object> preferenceValueAttributes);
// see above
boolean endOpenPass();
}
interface PreferenceStoreResolveVisitor
{
// Notifies the visitor that a new pass is commencing
void beginResolvePass();
// Called for every preference currently in the store
// The Preference p will be replaced with whatever the method returns.
Preference visitForResolve(Preference p);
// see above
boolean endResolvePass();
}
interface PreferenceStoreCloseVisitor
{
// Notifies the visitor that a new pass is commencing
void beginClosePass();
// Called for every preference currently in the store
// The store will write to disk whatever this method returns.
Preference visitForClose(Preference p);
// see above
boolean endClosePass();
} |
Persistence
Preferences are considered immutable. All changes to preferences should go through a UserPreferences facade which is responsible for updating the store.
...