Crear Configuraciones
A continuación se presenta un ejemplo de cómo agregar una configuración, en este caso una configuración de CsmAgent que será gestionada por la plataforma. Debe configurar un proyecto de dominio y un proyecto de repositorio.
Configuración del Proyecto de Dominio
Para añadir una configuración que deba ser gestionada por el Dynamic Processing Settings Plataforma que necesita crear lo siguiente:
-
Definición de Configuración
-
Objeto de Dominio
-
Campos de búsqueda para la configuración
Definición de 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 contenido de un objeto de configuración y debe contener todos los atributos relevantes para la configuración que desea 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);
}
}
Configuración de clase:
@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
Defina los campos que son buscables en la configuración; en este caso, el CsmAgent puede ser buscado 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 usted define para la configuración, todas las configuraciones son buscables a través de CommonSearchFields(estado, entidadDeProcesamiento, activoDesde y fuente)
@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;
}
}
A continuación se indica al marco 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 debe actualizar el mapa de campos de búsqueda que especifica la ruta al campo buscable desde la perspectiva de una configuración.
@PostConstruct
void updateSearchFieldsMap() {
settingSearchFieldsMapper.putMapping(CsmAgentSettingSearchFields.CSM_AGENT_ID.getName(), "payload.csmAgentId");
}
Configuración del Proyecto del Repositorio
Además, se debe definir la siguiente infraestructura de lectura:
-
Repositorio
-
ModelEntity
-
ModelEntityProvider
-
IndexInicializador
Repositorio
Repositorio, 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 la carga útil para 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 apropiado ModelEntity, basado en el identificador que se introduce
@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
El Inicializador de Índices 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);
}
}