Documentation for a newer release is available. View Latest

Crear configuraciones

El siguiente es un ejemplo de cómo agregar una configuración; en este caso, una configuración de CsmAgent que será gestionada por la plataforma. Debes configurar un proyecto de dominio y un proyecto de repositorio.

Configuración del proyecto de dominio

Para agregar una configuración que sea gestionada por la plataforma Dynamic Processing Settings, debes crear lo siguiente:

  • Definición de la configuración

  • Objeto de dominio

  • Campos de búsqueda para la configuración

Definición de la configuración

Especifica cómo calcular la clave lógica única para la configuración y asocia todos los demás componentes (objeto de dominio y campos de búsqueda) al concepto de configuración.

    @Bean
    SettingDefinition csmAgentSettingDefinition(final Notifier systemEventSender) {
        return SettingDefinition.<CsmAgent>builder()
                .name("csmagent")
                .clazz(CsmAgent.class)
                .idFunction(setting -> setting.getProcessingEntity() + "-" + setting.getPayload().getCsmAgentId())
                .approvalFunction((requiresApproval, persistanceId, inputSetting) -> CompletableFuture.completedStage(requiresApproval))
                .searchableFields(CsmAgentSearchableFields.class)
                .notificationFunction(systemEventSender::notify)
                .build();
    }

Objeto de dominio

Este será el payload de un objeto de configuración y debe contener todos los atributos relevantes para la configuración que deseas definir.

@Data
@Builder(toBuilder = true)
public class CsmAgent {
    @NotNull
    private String csmAgentId;
    private String csmAgentBic;
    @Size(max = 70)
    private String csmAgentName;
    @NotNull
    @Size(max = 35)
    private String csmAgentType;
    @NotNull
    @Size(max = 15)
    private String csmParticipantIdentifierType;
    @NotNull
    @Size(max = 35)
    private String csmAgentConnector;
    @Size(max = 70)
    private String csmAgentConnectorAddress;
    @Size(min=1)
    @Valid
    private List<CsmAgentMessageStandard> csmAgentMessageStandards;
    private Boolean onUsCSM;
    private Boolean higherParticipantLimitNotAllowed;
    private Boolean instantPayments;

    @Data
    @Builder
    public static class CsmAgentMessageStandard {
        @NotNull
        @Size(max = 35)
        private String messageStandard;
        @NotNull
        @Size(max = 35)
        private String messageStandardVersion;
        @NotNull
        private Instant activeFrom;
    }

    public boolean isHigherParticipantLimitNotAllowed() {
        return BooleanUtils.isTrue(higherParticipantLimitNotAllowed);
    }

    public boolean isOnUsCSM() {
        return BooleanUtils.isTrue(onUsCSM);
    }

    public boolean isInstantPayments() {
        return BooleanUtils.isTrue(instantPayments);
    }


}

Clase Setting:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Setting <T> implements Serializable {
    private String id;
    @Size(max = 15, min = 1)
    private String processingEntity;
    private Instant activeFromDate;
    private String source;
    private String status;
    private int version;
    private String createdBy;
    private String rejectedBy;
    private String approvedBy;
    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
    private T payload;

    @JsonIgnore
    public boolean isActive() {
        return "ACTIVE".equalsIgnoreCase(status);
    }
}

Campos de búsqueda

Define los campos por los que se puede buscar la configuración; en este caso, CsmAgent se puede buscar por CsmAgentId.

package com.iconsolutions.ipf.dynamicsettings.search;

public enum CsmAgentSettingSearchFields implements SearchField {
    CSM_AGENT_ID;

    @Override
    public String getName() {
        return this.name();
    }
}

Además de los campos de búsqueda que definas para la configuración, todas las configuraciones se pueden buscar mediante CommonSearchFields (status, processingEntity, activeFrom y source).

@Data
public class CommonSearchableFields implements SearchableFields {
    private String status;
    private String processingEntity;
    private Instant activeFrom;
    private List<String> idList;
    @Pattern(regexp = "import|manual", flags = Pattern.Flag.CASE_INSENSITIVE)
    private String source;

    public CommonSearchableFields populateFromRequest(ServerRequest serverRequest) {
        CommonSearchableFields commonSearchableFields = newInstance();
        serverRequest.queryParam("status").ifPresent(commonSearchableFields::setStatus);
        serverRequest.queryParam("processingEntity").ifPresent(commonSearchableFields::setProcessingEntity);
        serverRequest.queryParam("source").ifPresent(commonSearchableFields::setSource);
        serverRequest.queryParam("activeFrom").ifPresent(activeFrom1 -> commonSearchableFields.setActiveFrom(Instant.parse(activeFrom1)));
        return commonSearchableFields;
    }

    public CommonSearchableFields newInstance() {
        return new CommonSearchableFields();
    }

    @Override
    public List<Criterion> criteria() {
        final List<Criterion> criteria = new ArrayList<>();

        if (status != null) {
            criteria.add(Criterion.equalTo(SettingSearchFields.STATUS, status));
        } else {
            criteria.add(Criterion.notEqualTo(SettingSearchFields.STATUS, "INITIAL"));
        }

        if (activeFrom != null) {
            criteria.add(Criterion.gte(SettingSearchFields.ACTIVE_FROM, activeFrom));
        }

        if (source != null) {
            criteria.add(Criterion.equalTo(SettingSearchFields.SOURCE, source));
        }

        if (processingEntity != null) {
            criteria.add(Criterion.equalTo(SettingSearchFields.PROCESSING_ENTITY, processingEntity));
        }

        if(idList != null) {
            criteria.add(Criterion.in(SettingSearchFields.ID, idList));
        }


        return criteria;
    }
}

Lo siguiente le indica al framework cómo extraer los campos de búsqueda de las solicitudes recibidas.

@Data
public class CsmAgentSearchableFields extends CommonSearchableFields {
    private String csmAgentId;

    @Override
    public CsmAgentSearchableFields populateFromRequest(ServerRequest serverRequest) {
        CsmAgentSearchableFields searchableFields = (CsmAgentSearchableFields) super.populateFromRequest(serverRequest);
        serverRequest.queryParam("csmAgentId").ifPresent(searchableFields::setCsmAgentId);
        return searchableFields;
    }

    @Override
    public CsmAgentSearchableFields newInstance() {
        return new CsmAgentSearchableFields();
    }

    @Override
    public List<Criterion> criteria() {
        final List<Criterion> criteria = new ArrayList<>(super.criteria());

        if (csmAgentId != null) {
            criteria.add(equalTo(CsmAgentSettingSearchFields.CSM_AGENT_ID, csmAgentId));
        }


        return criteria;
    }
}

También debes actualizar el mapa de campos de búsqueda, que especifica la ruta al campo con capacidad de búsqueda desde la perspectiva de una configuración.

    @PostConstruct
    void updateSearchFieldsMap() {
        settingSearchFieldsMapper.putMapping(CsmAgentSettingSearchFields.CSM_AGENT_ID.getName(), "payload.csmAgentId");
    }

Configuración del proyecto de repositorio

Adicionalmente, se debe definir la siguiente infraestructura del lado de lectura:

  • Repository

  • ModelEntity

  • ModelEntityProvider

  • IndexInitialiser

Repository

Repository, que extiende ReactiveCRUDRepository y expone la funcionalidad de consulta de la configuración almacenada en la base de datos.

public interface CsmAgentSettingsRepository extends SettingRepository<CsmAgentSettings> {

    String CSMAGENT = "csmagent-";

    Flux<CsmAgentSettings> findAll(Sort sort);

    @Override
    default boolean supports(String id) {
        return id.toLowerCase().contains(CSMAGENT);
    }
}

ModelEntity

ModelEntity define cómo se representará la configuración en la base de datos y también define cómo se crea/actualiza el payload de las configuraciones.

@Document(collection = "settings-csm-agent")
@Data
public class CsmAgentSettings extends MongoSettingReadModelEntity<CsmAgent> {

    @Override
    protected Supplier<CsmAgent> payloadCreator() {
        return () -> CsmAgent.builder().build();
    }

    @Override
    protected BiFunction<Event, CsmAgent, CsmAgent> payloadUpdater() {
        return (event, csmAgent) -> csmAgent;
    }

}

ModelEntityProvider

ModelEntityProvider es responsable de crear el ModelEntity apropiado, basado en el identificador que se recibe como entrada.

@Component
public class CsmAgentMongoSettingModelEntityProvider implements MongoSettingModelEntityProvider {
    // "-" suffix added to avoid partial match e.g. csmagent matching csmagentcurrency
    private static final String CSMAGENT = "csmagent-";

    @Override
    public MongoSettingReadModelEntity provide() {
        return new CsmAgentSettings();
    }

    @Override
    public Class<? extends MongoSettingReadModelEntity> getEntityClazz() {
        return CsmAgentSettings.class;
    }

    @Override
    public boolean supports(String id) {
        return id.toLowerCase().contains(CSMAGENT);
    }
}

IndexInitialiser

Index Initialiser es responsable de crear índices en la colección.

@Slf4j
@AllArgsConstructor
public class CsmAgentMongoSettingRecordIndexInitialiser {

    private static final String STATUS = "status";
    private static final String PROCESSING_ENTITY = "processingEntity";
    private static final String PAYLOAD_CSM_AGENT_ID = "payload.csmAgentId";
    private static final String COLLECTION_NAME = "CsmAgentSettings";
    private final ReactiveMongoTemplate reactiveMongoTemplate;
    private final RepositoryRetryProvider repositoryRetryProvider;

    @EventListener(ContextRefreshedEvent.class)
    public void initialise() {
        log.info("creating indexes");
        final ReactiveIndexOperations indexOperations = reactiveMongoTemplate
                .indexOps(CsmAgentSettings.class);

        createIndex(indexOperations, STATUS, COLLECTION_NAME, repositoryRetryProvider);
        createIndex(indexOperations, PROCESSING_ENTITY, COLLECTION_NAME, repositoryRetryProvider);
        createIndex(indexOperations, PAYLOAD_CSM_AGENT_ID, COLLECTION_NAME, repositoryRetryProvider);
    }


}