Documentation for a newer release is available. View Latest

Recuperar datos del padre desde un hijo

Por defecto, cuando un flow padre llama a un flow hijo, las estructuras de datos relacionadas con el flow padre no están disponibles en el flow hijo.

Una de las situaciones en las que podríamos querer recuperar las estructuras de datos del padre es en bulking/debulking; el procesamiento se divide por niveles con muchos C-Levels (información del acreedor) requeridos por cada B-Level (información del deudor). Al procesar el C-Level es necesario acceder a la información del deudor para la contabilización/liquidación.

Acceso al flow padre

A falta de otras alternativas, para acceder a estas estructuras (como el MDS y el PDS) sería necesaria una llamada a través de un dominio externo a ODS para recuperar la información.

Sin embargo, hay formas mejores y más eficientes de recuperar esta información:

1) Si el padre está desplegado en un servicio de procesamiento diferente, entonces debemos usar el transactionOperation API desplegado en el servicio del padre, que contiene un endpoint que permite recuperar el aggregate.

2) Si el padre está presente en el mismo servicio de procesamiento. En esta situación, se pueden recuperar las estructuras de datos desde la flo-domain API.

Usar la flo-domain API

NOTA: Esto asume que el flow padre está disponible en el mismo servicio de procesamiento.

Una alternativa a una llamada a ODS para recuperar los datos es usar una llamada a getAggregate desde la API flo-domain, cuando tanto el flow padre como el hijo están en el mismo servicio de procesamiento.

Esto aprovecha el hecho de que una acción hija conoce el flow Id que la llamó y, como tal, se pueden recuperar los datos.

La clase Aggregate especificada como parámetro en la llamada pertenece al flow padre, aunque, por supuesto, la recuperación se produce durante el procesamiento dentro de la acción del flow hijo.

En la situación siguiente, TransactionFlow está siendo llamado desde BatchFlow, por lo que el aggregate que se recupera es BatchFlowAggregate.

import debulkexamplemodel.domain.DebulkexamplemodelModelOperations;
[...]
debulkexamplemodelModelOperations.getAggregate(parentId, BatchFlowAggregate.class)

Procesar los valores

Los valores MDS y PDS se filtran del aggregate del padre para su uso:

return debulkexamplemodelModelOperations.getAggregate(parentId, BatchFlowAggregate.class)
                .thenAccept(batchFlowAggregate -> {
                    MdsWrapper<PaymentInstruction30> parentMdsValues = batchFlowAggregate.getPain001Instruction();
                    List<? extends DataElementWrapper<?>> parentPdsValues = batchFlowAggregate.businessData().values()
                            .stream()
                            .filter(dataElementWrapper -> dataElementWrapper.getCategory().equals("PROCESSING_DATA_STRUCTURE"))
                            .toList();
                });

Usar la caché

Además de esto, si el mismo parent id se recupera múltiples veces, el uso de caché sería útil. Debe usarse ipf-cache para esto, a fin de reducir el uso repetido de getAggregate.

Para facilitarlo, se puede añadir la siguiente entrada al pom.xml

<dependency>
    <groupId>com.iconsolutions.ipf.core.platform</groupId>
    <artifactId>ipf-cache-api</artifactId>
</dependency>
<dependency>
    <groupId>com.iconsolutions.ipf.core.platform</groupId>
    <artifactId>ipf-cache-caffeine</artifactId>
</dependency>

Más documentación sobre cómo configurar la caché para su uso está aquí.

Haciendo esto, se puede utilizar una implementación que evite los inconvenientes asociados a volver a leer desde el aggregate. Más detalles aquí.

Implementar la caché

Cuando todo esto se integra en el ActionAdapter para el flow hijo, podemos tener algo como lo siguiente:

    private final DebulkexamplemodelModelOperations debulkexamplemodelModelOperations;
    private final CacheAdapter<String, MdsPdsWrapper> cacheAdapter;
private Optional<MdsPdsWrapper> getFromCache(String parentId) {
    var mdsPdsWrapper = cacheAdapter.get(parentId);
    if (mdsPdsWrapper.isPresent()) {
        log.debug("Existing MdsPdsWrapper retrieved from cache; parentId:{} mdsPdsWrapper:{}", parentId, mdsPdsWrapper);
    }
    return mdsPdsWrapper;
}
CompletionStage<Void> getFromCacheOrLoad(String parentId) {
    return getFromCache(parentId).isPresent() ?
            CompletableFuture.completedFuture(null) :
            retrieveParentMdsPdsWrapper(parentId);
}
private CompletionStage<Void> retrieveParentMdsPdsWrapper(String parentId) {
    return debulkexamplemodelModelOperations.getAggregate(parentId, BatchFlowAggregate.class)
            .thenAccept(batchFlowAggregate -> {
                MdsWrapper<PaymentInstruction30> parentMdsValues = batchFlowAggregate.getPain001Instruction();
                List<? extends DataElementWrapper<?>> parentPdsValues = batchFlowAggregate.businessData().values()
                        .stream()
                        .filter(dataElementWrapper -> dataElementWrapper.getCategory().equals("PROCESSING_DATA_STRUCTURE"))
                        .toList();
                MdsPdsWrapper mdsPdsWrapper = new MdsPdsWrapper(parentMdsValues, parentPdsValues);
                cacheAdapter.put(parentId, mdsPdsWrapper);
                log.debug("Loaded into cache -- parentId:{} mdsPdsWrapper:{}", parentId, mdsPdsWrapper);
            });
}

NOTA: La clase MdsWrapper es un POJO que se añadió para simplificar los valores almacenados en la caché.