Validación
La validación es una gran parte del ISO20022 Message model. Existen numerosos y crecientes niveles de "validez" que pueden aplicarse a un mensaje. Diferentes niveles de validación suelen ser realizados por diferentes componentes de software.
Niveles de validación ISO20022
La tabla siguiente muestra exactamente la enumeración de Message Validity especificada por el ISO20022 Meta-Model; también hemos incluido notas adicionales y describimos qué componente de software IPF participa en confirmar cada Validation Level.
Validation level |
ISO20022 description |
IPF implementation |
Related IPF component |
NO_VALIDATION |
The message instance is not validated. |
Something that is not Syntax Valid cannot be assumed to be parseable, failure is thrown at the deserialisation layer. |
|
SYNTAX_VALID |
The message instance has its syntax validated. |
Syntax valid simply means the message has been successfully deserialised into a Java representation. |
|
[[ _schema_valid]]SCHEMA_VALID |
The message instance is Syntax Valid plus validated against the XSD Message Schema. |
||
[[ _message_valid]]MESSAGE_VALID |
The message instance is Schema Valid plus validated against the Message Rules. |
This is the application of the ISO20022 Constraints against Message Components and Datatypes |
|
[[ _rule_valid]]RULE_VALID |
The message instance is Message Valid plus validated against the Business Rules. |
This is the application of additional Bank Rules / application Rules. |
|
MARKET_PRACTICE_VALID |
The message instance is Message Valid plus validated against the Market Practices. |
This is the application of additional Market Scheme specific rules |
|
BUSINESS_PROCESS_VALID |
The message instance is Message Valid plus validated against the Message Choreography. |
This is whether the message is valid within the context of it’s intended exchange. For example a randomly received orphan pacs.002 may "technically" be market valid, but it is not "valid" in the absence of an originating message) |
|
COMPLETELY_VALID |
The message instance is Message Valid plus validated against all Rules and Market Practices. |
Como se describió arriba, la comprobación SYNTAX_VALID suele realizarse en el momento de la deserialización de un mensaje externo, especialmente con una aplicación que utiliza un lenguaje tipado estáticamente como Java para modelar la abstracción del mensaje. Si hemos podido deserializar el mensaje en nuestro modelo Java, entonces es SYNTAX_VALID; luego vemos los tres niveles de validación siguientes, que se relacionan con la validez del contenido dentro del mensaje en aislamiento.
El IPF ISO20022 Message Model proporciona una clase de validación MessageComponentValidator que ofrece la posibilidad de validar una Message Definition o Message Component en cualquiera o en todos estos niveles.
Message Component Validator
La clase Message Component Validator ofrece la posibilidad de validar un objeto Message Definition (o Message Component individual). Admite validación para SCHEMA_VALID, MESSAGE_VALID y RULE_VALID. Las validaciones son configurables y se informan de forma independiente, de modo que el usuario tiene control total sobre qué validaciones deben realizarse en un momento dado.
Schema Rules y Message Rules se implementan como JSR303 Annotations en las clases Java de los Message Components. El Message Component Validator delega en una implementación Hibernate Validator la ejecución de estas reglas.
|
Niveles de validación
A menudo solo querrás realizar SCHEMA_VALID al recibir el mensaje externo y posponer MESSAGE_VALID hasta una etapa posterior del procesamiento, donde el contenido del mensaje puede haber sido enriquecido. El Message Component Validator está específicamente diseñado para admitir estos escenarios. |
Schema Rules
Esto suele denominarse "validar un mensaje contra un Schema", específicamente el XSD asociado a la Message Definition. Esta validación a menudo incluye, entre otros:
-
Comprobaciones de rango
-
Nullability
-
Restricciones de patrón
-
Modality
-
Cardinality
-
Enumeration
-
Exclusivity
Dentro de la implementación de IPF ISO20022 Message Model, las validaciones definidas por los XSD schemas se implementan completamente en las clases Java del Message Model como JSR303 Bean Validation Annotations. No se proporcionan XSDs para las Message Definitions como parte de IPF ISO20022 Message Model. No es necesario validar las Message Definitions proporcionadas por este modelo contra los XSD de ISO20022, ni es posible debido a los Normalised Types y la eliminación de namespacing.
La validación debe realizarse exclusivamente mediante Message Component Validator.
|
Grupos de validadores JSR303
Las Schema Rules se implementan como JSR303 Annotations bajo el grupo default. Esto significa que cualquier intento de validar un Message Component directamente contra un Hibernate Validator (u otra implementación) validará el objeto contra las Schema Rules apropiadas. Esto es similar, aunque con un alcance ligeramente más estricto, al conjunto predeterminado de JSR303 Annotations que XJC suele adjuntar. Las anotaciones predeterminadas proporcionadas por XJC NO respetan algunas Schema Validations como Choice Components y exclusividad; históricamente esto se dejaba al proceso de validación XSD, fuera de los validadores JSR303 Bean. |
Incluir Schema Rules para la validación
Para incluir Schema Rules como parte del alcance de validación para una solicitud de validación, el parámetro ValidationOptions debe configurarse para requerir Schema Rules
Construimos un objeto ValidationOptions que habilita la validación de Schema Rules; esto puede hacerse explícitamente como se muestra aquí o mediante uno de los perfiles comunes detallados más abajo en Common ValidationOptions.
Definición de ValidationOptions
// Only enable Schema Rule Validation
ValidationOptions onlyValidateSchemaRules = ValidationOptions.builder()
.applySchemaValidation(true)
.applyBusinessRuleValidation(true)
.applyMessageRuleValidation(false)
.build();
Validación de un objeto de mensaje
// This will fail Schema Validation as GroupHeader and PaymentInstruction elements are not present
CustomerCreditTransferInitiationV09 ccti = CustomerCreditTransferInitiationV09.builder().build();
MessageComponentValidator validator = ISO20022MessageModel.getInstance().validator();
ValidationResult<CustomerCreditTransferInitiationV09> result = validator.validate(ccti, onlyValidateSchemaRules);
Verificación del resultado
El objeto de respuesta ValidationResult contiene niveles enumerados separados que indican el resultado de Schema Rule, Message Rule y Business Rule, ya sea VALID, INVALID o NOT_APPLIED si no se solicitó un conjunto de reglas.
La respuesta también contiene listas separadas de cada tipo de Violation y una lista agregada de todas las infracciones para mayor comodidad.
|
¿Entonces era válido?
El MessageComponentValidator proporciona respuestas granulares que detallan si el mensaje de entrada es válido para diferentes niveles. Si bien el resultado proporciona una propiedad result.isValid(), esto debe considerarse cuidadosamente en el contexto de la configuración de ValidationOptions solicitada. |
Las infracciones devueltas en este ejemplo muestran que la instancia de Message no era válida debido a dos Schema Violations independientes (violación de nullability para Group Header y Payment Instruction)
ValidationResult.ValidationLevelResult schemaValid = result.getSchemaValid(); // INVALID
Violation<CustomerCreditTransferInitiationV09> grpHdrViolation = result.getSchemaViolations().get(0);
String name1 = grpHdrViolation.getName(); // {javax.validation.constraints.NotNull.message}
String message1 = grpHdrViolation.getMessage(); // "must not be null"
String properyPath1 = grpHdrViolation.getPropertyPath(); // "grpHdr"
ValidationType type1 = grpHdrViolation.getType(); // SCHEMA_RULE
ConstraintViolation<CustomerCreditTransferInitiationV09> jsrViolation1 = grpHdrViolation.getJsr303ConstraintViolation() ; // Original Validation details
Violation<CustomerCreditTransferInitiationV09> pmtInfViolation = result.getSchemaViolations().get(1);
String name2 = pmtInfViolation.getName(); // {javax.validation.constraints.NotNull.message}
String message2 = pmtInfViolation.getMessage(); // "must not be null"
String properyPath2 = pmtInfViolation.getPropertyPath(); // "pmtInf"
ValidationType type2 = pmtInfViolation.getType(); // SCHEMA_RULE
ConstraintViolation<CustomerCreditTransferInitiationV09> jsrViolation2 = grpHdrViolation.getJsr303ConstraintViolation() ; // Original Validation details
Message Rules
Las Message Rules son la parte más interesante de las validaciones del ISO20022 Message Model. Son reglas lógicas formales definidas contra Message Definitions o Message Components individuales. Sin embargo, no están codificadas en los XSDs tradicionales, ya que a menudo no pueden articularse completamente en XSD del mismo modo que una Schema Rule. Por ejemplo, presencia condicional a través de elementos hijos anidados.
Estas reglas se definen dentro del Meta-Model y E-Repository subyacentes de ISO20022, donde se conocen como Constraints. En el IPF ISO20022 Message Model estas reglas se implementan como JSR303 "triggers" Annotations, un Message Rule Cache y interfaces dedicadas que deben implementarse para cada Message Rule.
Visión general
El diagrama siguiente muestra una visión de alto nivel de las diversas clases involucradas en la definición de una implementación de Message Rule.
Para una Message Rule determinada, por ejemplo "Identification Or Proxy Presence Rule", generamos tres clases.
-
Una interfaz específicamente para la regla, que amplía una interfaz Constraint de Icon. Estas reglas son implementadas manualmente por el equipo de ingeniería de IPF para una Message Definition dada y se proporcionan como parte del paquete Message-Model.
-
Una Jsr303 Annotation que decora el Message Component asociado, en este ejemplo CashAccount41.
-
Una clase ConstraintValidator, que implementa el contrato Javax ConstraintValidator para la JSR303 Annotation mencionada.
La implementación de ConstraintValidator delega la ejecución real de la regla en una implementación del Constraint generado (1). La implementación de ConstraintValidator intenta resolver una implementación en tiempo de ejecución de la regla buscando una implementación registrada dentro de una instancia de MessageRuleCache. La implementación de ConstraintValidator puede ser instruida por las ValidationOptions de MessageComponentValidator para fallar o omitir si no se puede resolver una implementación desde el Message Rule Cache en tiempo de ejecución.
|
El desacoplamiento de las implementaciones de Message Rule en tiempo de ejecución de los "triggers" JSR303 proporciona la capacidad de implementación rápida de nuevas Message Definitions, adopción gradual e implementación de Message Rules, y también la posibilidad de actualizar y cambiar implementaciones de Message Rule sin necesidad de una publicación mayor del Message Model. |
Registro de una Message Rule
|
¿Qué Message Rule están implementadas?
Las implementaciones de las Message Rules para todas las Message Definitions soportadas se proporcionarán como parte del IPF ISO20022 Message Model, aunque esto se está publicando de forma incremental y aún no está completo. |
Si bien las Message Rules están implementadas como parte del ISO20022 Message Model proporcionado, documentamos el proceso aquí por completitud y como referencia en caso de que sea necesario implementar nuevas o alternativas Message Rules a nivel de proyecto.
Primero identificamos una Message Rule a implementar; en este ejemplo usaremos una regla que aplica a un Message Component Cash Account, donde al menos la información de identificación de la cuenta o la información de proxy debe proporcionarse. Estas reglas pueden verse por la presencia de la JSR303 Annotation asociada en el propio Message Component.
Observa cómo CashAccount41 tiene una @IdentificationOrProxyPresenceRule para ser aplicada
...
@IdentificationOrProxyPresenceRule(groups = MessageRule.class)
public class CashAccount41 implements Serializable {
...
}
Para encontrar el Constraint asociado que necesita implementarse, que se dispara cuando se valida este Message Component, simplemente mira en el paquete padre una Interface con el mismo nombre que la Annotation
com.iconsolutions.iso20022.message.components.cash_account.cash_account41.jsr303.IdentificationOrProxyPresenceRule
vs.
com.iconsolutions.iso20022.message.components.cash_account.cash_account41.IdentificationOrProxyPresenceRule
A continuación se muestra el Constraint IdentificationOrProxyPresenceRule que debemos implementar.
Muchas de las Constraints se documentan con una descripción pseudo formal del requisito. Esto puede ser crucial para resaltar escenarios de prueba adecuados para validar estas reglas.
package com.iconsolutions.iso20022.message.components.cash_account.cash_account41;
/*Generated by MPS */
import com.iconsolutions.iso20022.message.meta.validation.Constraint;
public interface IdentificationOrProxyPresenceRule extends Constraint<CashAccount41> {
/**
* Identification must be present or proxy must be present.
*
* <pre>
*
* <RuleDefinition>
* <SimpleRule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="SimpleRule">
* <mustBe>
* <connector>OR</connector>
* <BooleanRule xsi:type="Presence">
* <leftOperand>/Identification</leftOperand>
* </BooleanRule>
* <BooleanRule xsi:type="Presence">
* <leftOperand>/Proxy</leftOperand>
* </BooleanRule>
* </mustBe>
* </SimpleRule>
* </RuleDefinition>
*
* </pre>
*/
boolean isValid(CashAccount41 cashAccount41);
}
Luego podemos escribir una implementación concreta de esta regla, por ejemplo:
Implementación de una Message Rule
package com.iconsolutions.iso20022.message.components.cash_account.cash_account41;
public class IdentificationOrProxyPresenceRuleImpl implements IdentificationOrProxyPresenceRule {
@Override
public boolean isValid(CashAccount41 cashAccount41) {
return cashAccount41.getId() != null || cashAccount41.getPrxy() != null;
}
}
Estas reglas se probarán de forma independiente como parte de la producción del IPF ISO20022 Message Model.
Registro automático de Message Rules
El MessageComponentValidator está configurado por defecto para poblar ávidamente el MessageRuleCache con implementaciones de los Constraints. Lo hace usando Reflection (escaneando el classpath en busca de posibles implementaciones de las Constraint Interfaces) en el momento en que se inicializa ISO20022MessageModel.
Tiene lógica para detectar candidatos duplicados y también registrará mensajes informativos durante el arranque si no se han implementado todas las reglas.
Como tal, mientras la instancia de ISO20022MessageModel use la inicialización predeterminada y, por lo tanto, ScanningRuleCacheInitializer, las implementaciones deberían ser detectadas y aplicadas automáticamente.
Validación contra Message Rules
Construimos un objeto ValidationOptions que habilita la validación de Message Rule; esto puede hacerse explícitamente como se muestra aquí o mediante uno de los perfiles comunes.
Configuración de Validation Options
ValidationOptions onlyMessageRules = ValidationOptions.builder()
.applyMessageRuleValidation(true)
.failIfMessageRulesHaveNotBeenImplemented(true)
.applyBusinessRuleValidation(false)
.applySchemaValidation(false)
.build();
A continuación, validamos el Message Component CashAccount41
Validación de un mensaje
CashAccount41 cashAccount41 = CashAccount41.builder().build();
ValidationResult<CashAccount41> result = validator.validate(cashAccount41, onlyMessageRules);
Luego inspeccionamos la respuesta de validación y confirmamos que este mensaje no es válido ya que viola la Message Rule mencionada (entre varias otras)
Verificación del resultado
List<Violation<CashAccount41>> messageRuleViolations = result.getMessageRuleViolations();
Violation<CashAccount41> violation = messageRuleViolations.get(0);
String name = violation.getName(); // "IdentificationOrProxyPresenceRule"
String message1 = violation.getMessage(); // "IdentificationOrProxyPresenceRule"
String properyPath = violation.getPropertyPath(); // ""
ValidationType type = violation.getType(); // MESSAGE_RULE
ConstraintViolation<CashAccount41> jsrViolation1 = violation.getJsr303ConstraintViolation() ; // Original Validation details
Si alguna Message Rule no ha sido implementada, se proporcionarán como parte de la respuesta mediante el método siguiente.
Business Rules
Las business rules son reglas adicionales a nivel de aplicación que pueden aplicarse a los ISO20022 Messages para una implementación de negocio específica. Estas reglas son específicas del proyecto y podrían ser cosas como:
-
Comprobación de límites para imponer un tope al monto total de la transacción
-
Exclusión de BIC / IBAN
-
Restricción de ciertas monedas o códigos de compensación para un tipo de pago determinado
-
Asegurar que los identificadores propietarios cumplan con un patrón personalizado
Implementación de una Business Rule
Las Business Rules, a diferencia de Schema Rules o Message Rules, no se invocan mediante JSR303 Annotations, ya que estas reglas se definen como parte del proyecto implementador y se registran contra el tipo de destino
|
Clases objetivo de Business Rule
Las Business Rules se evalúan únicamente contra el tipo de solicitud exacto; no se propagan a clases hijas del mismo modo que las Message Rules o Schema Rules. Hasta que se realice esta mejora, se recomienda usar la clase de nivel superior Message Definition como objetivo para cada Business Rule |
A continuación creamos una nueva Business Rule, implementando la interfaz BusinessRule<T>, que requiere la implementación de un único método para realizar la validación. Pueden devolverse múltiples Violations desde una sola regla, cada una con sus propios detalles. La interfaz BusinessRule contiene métodos auxiliares como singleViolation() para construir las Violations.
Definición de una Business Rule
BusinessRule<CustomerCreditTransferInitiationV09> msgIdMustStartWithApple = new BusinessRule<>() {
@Override
public List<Violation<CustomerCreditTransferInitiationV09>> apply(CustomerCreditTransferInitiationV09 message) {
if (!message.getGrpHdr().getMsgId().startsWith("Apple"))
return singleViolation("MsgIdStartsWithApple", "grpHdr.MsgId", "Message ID should start with 'Apple'");
else {
return new ArrayList<>();
}
}
};
Una vez definida una Business Rule, debe registrarse en MessageComponentValidator a través de su dependencia BusinessRuleAccess.
Validación contra Business Rules
Para incluir Business Rule como parte del alcance de validación de una solicitud de validación, el parámetro ValidationOptions debe configurarse para requerir Business Rules
Construimos un objeto ValidationOptions que habilita la validación de BusinessRule; esto puede hacerse explícitamente como se muestra aquí o usando uno de los perfiles comunes descritos en Common Rule Configurations.
Configuración de Validation Options
ValidationOptions onlyValidateBusinessRules = ValidationOptions.builder()
.applyBusinessRuleValidation(true)
.applyMessageRuleValidation(false)
.applySchemaValidation(false)
.build();
Validación de un mensaje
CustomerCreditTransferInitiationV09 ccti = CustomerCreditTransferInitiationV09.builder()
.grpHdr(GroupHeader85.builder()
.msgId("Orange-s2ud2gs423d22").build())
.build();
ValidationResult<CustomerCreditTransferInitiationV09> result = validator.validate(ccti, onlyValidateBusinessRules);
Verificación del resultado
ValidationResult.ValidationLevelResult businessRulesValid = result.getBusinessRulesValid();// INVALID
Violation<CustomerCreditTransferInitiationV09> violation = result.getBusinessRuleViolations().get(0);
String name = violation.getName(); // MsgIdStartsWithApple
String message = violation.getMessage(); // "Message ID should start with 'Apple'"
String properyPath = violation.getPropertyPath(); // "grpHdr.MsgId"
ValidationType type = violation.getType(); // BUSINESS_RULE
Configuraciones comunes de ValidationOption
A menudo es tedioso definir manualmente la instancia de ValidationOptions cada vez. Se han proporcionado algunas instancias preconfiguradas como miembros estáticos de la clase ValidationOptions que pueden usarse de forma más conveniente; por ejemplo, las invocaciones siguientes realizan solo la validación de Schema, omitiendo Message Rules y Business Rules.
ValidationResult<CustomerCreditTransferInitiationV09> result = validator.validate(ccti, ValidationOptions.schemaValid());
A continuación se muestra una tabla que describe las configuraciones proporcionadas, su impacto y uso esperado.
|
Comportamiento predeterminado
Si no se proporciona un argumento ValidationOptions al validador, usa ruleValidLoose(). |
Este es el nivel más alto de validación que puede realizar Message Component Validator, pero no fallará si no se han implementado todas las Message Rules.
| Config | Description | Include Scheme Rules | Include Message Rules | Include Business Rules | Fail If Message Rules are not implemented |
|---|---|---|---|---|---|
schemaValid() |
Only performs Schema validation |
Y |
N |
N |
N |
messageValid() |
Additionally, performs validation against Message Rules |
Y |
Y |
N |
Y |
ruleValid() |
Additionally, performs validation against Business Rules |
Y |
Y |
Y |
Y |
[[ _rule_valid_Loose]] ruleValidLoose() |
As ruleValid(), but will not fail if not all Message Rules have been implemented. |
Y |
Y |
Y |
N |