Skip to main content
Datastore customizations are DatastoreConfiguratorConsumer beans, applied to the datastore in a defined order. The order decides where an appended field lands in a store. It also decides which customization wins when two of them insert after the same field. This ordering contract is available from Atoti FRTB 6.0.10. For how to write a customization, see Customizing the datastore with the datastore helper.

How are customizations ordered?

A datastore customization is a com.activeviam.tools.datastore.DatastoreConfiguratorConsumer bean. DatastoreCustomisationsConfig injects every one of these beans as a List<DatastoreConfiguratorConsumer>. That configuration class belongs to the frtb-starter module, in the package com.activeviam.frtb.starter.cfg.impl. It applies each consumer to the IDatastoreConfigurator in list order. No qualifier is needed. From Atoti FRTB 6.0.10 the list is no longer filtered on @Qualifier(SP_QUALIFIER__CUSTOMISATIONS), and that constant is deprecated for removal. A bean that still carries it is applied as before. Spring sorts the injected list with AnnotationAwareOrderComparator. That comparator reads the org.springframework.core.annotation.Order annotation declared on the @Bean factory method. A bean that is not qualified with customisations is never applied.

What are the sort rules?

Three rules follow from the Spring sort:
  1. A lower order value is applied earlier. A consumer at PROJECT (100) is applied before a consumer at SIGN_OFF (200).
  2. A bean with no @Order annotation is treated as Ordered.LOWEST_PRECEDENCE, which is Integer.MAX_VALUE. It is therefore applied after every annotated bean, not before.
  3. Beans sharing the same order value have no guaranteed relative order. The sort is stable, so the result follows bean registration order, but that is not a contract. Two customizations that change the field layout of the same store must be given distinct order values.

Which order values does Atoti FRTB use?

The order values are named constants of com.activeviam.frtb.core.cfg.ordering.DatastoreCustomisationSpringBeanOrder, in the frtb-core module. Every consumer bean shipped by Atoti FRTB declares the matching constant rather than a bare number, as in @Order(DatastoreCustomisationSpringBeanOrder.SIGN_OFF). A project customization declares @Order(DatastoreCustomisationSpringBeanOrder.PROJECT).

Why does the order matter?

The sign-off customization installs three key fields on the base store of a cube. Those fields are Source, Input type and Version. It is implemented by SignOffAnalysisConfig.signOffCustomisations in the Common Accelerator Library. In Atoti FRTB, all five sign-off customizations append those key fields at the end of their store. They pass a null previousField, so none of them insert. The following stores receive the sign-off key fields: signOffStores is the sixth sign-off consumer. It creates the sign-off digest stores instead of changing a base store. It therefore collides with nothing at SIGN_OFF.

When are customizations applied to the datastore?

A consumer usually does not modify a store when it is applied. It registers an intent on the IDatastoreConfigurator instead. DatastoreCustomisationsConfig calls addModifications first and buildSchemas second. Intents registered against a schema store are applied later, when that schema is built. signOffStores is the exception. It builds the sign-off digest store descriptions while it is applied, during addModifications. Those descriptions are complete once signOffStores has run, at SIGN_OFF (200). A customization ordered after it is never applied to those stores. At build time the intents are applied in a fixed phase order. Field updates come first, then removals, then insertions, then appends. The consumer order does not change that phase order. Three consequences follow:
  • Appended fields are sequenced by consumer order. They are collected into a list in the order their customization was applied. The list is then added at the end of the store. This is why SIGN_OFF works for the sign-off beans: the three key fields land after every field appended at a lower order.
  • Inserted fields are positioned by their anchor field, not by consumer order. The anchor is resolved at build time against the field list. The result is the same whichever order the consumer was applied in.
  • For insertions, consumer order decides which customization wins an anchor collision. Insertions are held in a map keyed by the anchor field name. One store therefore carries only one insertion per anchor. When two customizations insert after the same anchor of the same store, the later consumer wins. The earlier insertion is dropped without an error.
Removals are applied before insertions. Removing a field that another customization uses as its anchor drops that insertion. That happens whatever order either consumer was applied in.

How to choose an order value for a project customization

  • An appended field lands before the sign-off key fields at any value below SIGN_OFF (200). PROJECT (100) is the band reserved for that.
  • Use a value above 200 for a field that must follow the sign-off key fields.
  • An inserted field is positioned by its anchor field, not by the order value. The order value matters only when another customization inserts after the same anchor of the same store.
  • A customization that extends the sign-off digest stores needs a value below SIGN_OFF (200). SignOffTaskConfig#signOffStores builds those stores while it is applied, so a later customization is dropped without an error.
The example below declares a project customization at PROJECT.