Adding a File

This page provides a description of how to load a new CSV file into a new datastore in Atoti CVA Risk Capital. It walks through every layer of the data load pipeline introduced after the migration to the DLC framework: a new store, a new publisher target, a new topic, and registration for either initial-load or on-demand loading. The techniques employed are generic examples that can be extended, adapted, and repeated for any use case.

Step 1 - Move the data files

Place the new CSV files under an appropriate folder in cvarc-application-tests/src/test/resources/data-samples/data/{AsOfDate}/. This example uses two files placed under the 2018-12-05 folder.

123_Custom_1.csv

AsOfDate RiskClass CustomProjected UselessData
2018-12-05 commodity 340000 x
2018-12-05 interest rate 2000 a

987_Custom_2.csv

AsOfDate RiskClass CustomProjected UselessData
2018-12-05 foreign exchange 12341234 z
2018-12-05 equity 222222222 f

note

UselessData will be ignored — the topic’s parser column list (Step 3) determines which columns are read.

Step 2 - Define the store and a reference

Add the new store and any references to existing stores in the addModifications() method of DatastoreCustomisationsConfig at cvarc-application/src/main/java/com/activeviam/cvarc/application/cfg/DatastoreCustomisationsConfig.java. This class lives in your project’s cvarc-application module and is intended to be edited directly.

@Override
public void addModifications(IDatastoreConfigurator configurator) {
    configurator.addStore(CVARCParameters.CVA_SA_SCHEMA_NAME, StartBuilding.store()
            .withStoreName("Custom")
            .withField("AsOfDate", LOCAL_DATE).asKeyField()
            .withField("RiskClass", STRING).asKeyField()
            .withField("CustomProjected", DOUBLE)
            .withValuePartitioningOn("AsOfDate")
            .build());

    configurator.addReference(CVARCParameters.CVA_SA_SCHEMA_NAME,
            configurator.referenceBuilder(CVARCParameters.CVA_SA_SCHEMA_NAME)
                    .fromStore(SAStoreNames.SA_BASE_STORE_NAME)
                    .toStore("Custom")
                    .withName("BaseStoreToCustom")
                    .withMapping(SAStoreNames.SA_BASE_AS_OF_DATE, "AsOfDate")
                    .withMapping(SAStoreNames.SA_BASE_RISK_CLASS, "RiskClass")
                    .build());
}

Step 3 - Define a publisher target, a source, and a topic

Create a new @Configuration class in cvarc-application/src/main/java/com/activeviam/cvarc/application/cfg/extensions/. It declares three DLC beans:

  • a TargetDescription — the publisher that writes parsed rows into the new store;
  • a LocalCsvSourceDescription — the source that scans CSV files under a directory;
  • a CsvTopicDescription — the topic that ties a file pattern to a parser and to the publisher target.

Mirror SASourceDescription (cvarc-starter/src/main/java/com/activeviam/cvarc/starter/cfg/impl/dlc/SASourceDescription.java) and TargetDescriptionsConfig (in the same package) for the canonical patterns.

package com.activeviam.cvarc.application.cfg.extensions;

import com.activeviam.database.datastore.api.IDatastore;
import com.activeviam.io.dlc.impl.description.source.LocalCsvSourceDescription;
import com.activeviam.io.dlc.impl.description.topic.CsvTopicDescription;
import com.activeviam.io.dlc.impl.description.topic.channel.ChannelDescription;
import com.activeviam.io.dlc.impl.description.topic.channel.publish.TargetDescription;
import com.activeviam.io.dlc.impl.description.topic.parser.CsvParserDescription;
import com.activeviam.io.dlc.impl.utils.NamedEntityResolverService;
import com.activeviam.source.common.api.impl.TuplePublisher;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.Set;

@Configuration
@RequiredArgsConstructor
public class CustomFileSourceDescription {

    public static final String CSV_TOPIC__CUSTOM = "Custom";
    public static final String CUSTOM_PUBLISHER = "customPublisher";
    public static final String CUSTOM_SOURCE_NAME = "customSource";

    private final IDatastore datastore;

    @Bean
    public TargetDescription customPublisher() {
        return TargetDescription.of(CUSTOM_PUBLISHER, "Custom",
                scope -> new TuplePublisher<>(datastore, "Custom"));
    }

    @Bean
    public LocalCsvSourceDescription customSourceDescription() {
        return LocalCsvSourceDescription.builder(CUSTOM_SOURCE_NAME, "./src/test/resources/data-samples/data")
                .topicsToInclude(Set.of(CSV_TOPIC__CUSTOM))
                .build();
    }

    @Bean
    public CsvTopicDescription customTopic(NamedEntityResolverService namedEntityResolver) {
        return CsvTopicDescription.builder(CSV_TOPIC__CUSTOM, "glob:**/*Custom*.csv")
                .parser(CsvParserDescription.builder().columns(
                        List.of("AsOfDate", "RiskClass", "CustomProjected")
                ).build())
                .channel(ChannelDescription.builder(namedEntityResolver.getTarget(CUSTOM_PUBLISHER)).build())
                .build();
    }
}

The parser’s columns(...) list determines which columns are read. Columns present in the file but absent from the list (e.g. UselessData) are skipped.

Step 4 - Wire the extension into ApplicationConfig

Add CustomFileSourceDescription to the @Import list of ApplicationConfig in cvarc-application/src/main/java/com/activeviam/cvarc/application/cfg/ApplicationConfig.java.

Step 5 - Register the topic for loading

A topic that has been declared but never registered for loading does nothing. There are two common ways to register it:

Path A - Initial-load via alias

AliasesDescriptionConfig (cvarc-starter/src/main/java/com/activeviam/cvarc/starter/cfg/impl/dlc/AliasesDescriptionConfig.java) groups topics under named aliases that InitialDataLoadConfig then loads at startup. Subclass it to append your new topic to an existing alias (or define a new one):

package com.activeviam.cvarc.application.cfg.extensions;

import com.activeviam.cvarc.starter.cfg.impl.dlc.AliasesDescriptionConfig;
import com.activeviam.io.dlc.impl.description.AliasesDescription;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.Set;

import static com.activeviam.cvarc.application.cfg.extensions.CustomFileSourceDescription.CSV_TOPIC__CUSTOM;

@Configuration
@Primary
public class ExtendedAliasesDescriptionConfig extends AliasesDescriptionConfig {

    @Bean
    @Override
    public AliasesDescription aliasesDescription() {
        return super.aliasesDescription().toBuilder()
                .alias(CSV_TOPIC__ALIAS__SA_DATA, Set.of(CSV_TOPIC__CUSTOM))
                .build();
    }
}

super.aliasesDescription().toBuilder() inherits every alias the parent declares; the additional .alias(...) call merges in the new topic. Add ExtendedAliasesDescriptionConfig to the @Import list of ApplicationConfig.

Path B - On-demand via Data Load Controller

For loads triggered by an event or REST call rather than at startup, declare an ApplicationRunner @Bean that calls the IDataLoadControllerService. Mirror InitialDataLoadConfig.initialDataLoad() (cvarc-starter/src/main/java/com/activeviam/cvarc/starter/cfg/impl/dlc/InitialDataLoadConfig.java):

@Bean
public ApplicationRunner loadCustomData(IDataLoadControllerService dlc) {
    return args -> {
        final DlcScope scope = new DlcScope();
        scope.put(AS_OF_DATE_SCOPE_KEY, "2018-12-05");
        dlc.execute(DlcLoadRequest.builder()
                .topics(CSV_TOPIC__CUSTOM)
                .scope(scope)
                .build());
    };
}

The same dlc.execute(...) call can be invoked from any Spring component (e.g. a REST controller) to load data on demand.

Step 6 - Expose the new fields

To expose the new store’s fields as hierarchies or measures, see Adding a Hierarchy and Adding New Cube Measures. Each cube’s selection must be extended to include a reference into the new store before the fields become reachable.