Les contrôles d’intégrités avec Scub Foundation – Partie 1

Introduction

Cet article est le premier d’une trilogie destinée à présenter le fonctionnement des contrôles d’intégrités avec Scub foundation. Ce premier article va définir les bases des contrôles d’intégrités et décrire les technologies et les processus utilisés. Dans un second article, nous verrons comment mettre en place la chaine de validation dans un projet noyau (core-implementation) et dans un dernier, comment gérer l’affichage des erreurs dans un client GWT.

Sommaire

Introduction
Contexte
Que sont les contrôles d’intégrités?
Un rapport complet
Revoir la façon d’écrire les règles métiers
Oval

Gestion dans la partie Noyau
Poser les contraintes dans les DTO
Utiliser les validateurs
La gestion des messages d’erreurs
Gérer les règles métiers qui ne sont pas dans les DTO
Les autres méthodes utiles des validateurs
Tester les contrôles d’intégrités avec JUnit

Gestion dans un client GWT
Utilisation du Callback prévu à cet effet
Utiliser le conteneur d’erreurs

Contexte

Dans une application informatique, un des points les plus importants est la gestion des contrôles métiers. D’un côté, les contrôles doivent être fait de manière efficace et fiable afin que le logiciel soit robuste et qu’il réponde aux attentes du client. D’un autre coté, les erreurs doivent être lisibles pour l’utilisateur et leur affichage ne doit pas être trop intrusif et contraignant. Il n’y a rien de plus agaçant qu’un formulaire qui gère les erreurs une par une.

Prenons l’exemple d’un formulaire de création de personne. On l’envoit une première fois et l’application nous retourne l’erreur “Le prénom est requis”. Après avoir rempli le prénom et renvoyé le formulaire, le logiciel nous affiche une seconde erreur “Le format de la date est invalide”. L’utilisateur se serait bien passé d’envoyer deux fois le formulaire et l’on peut comprendre assez facilement son énervement si le formulaire contient encore d’autres contrôles. La liste peut parfois être longue!

Aujourd’hui, l’utilisateur veut avoir accès au plus d’informations possibles sans pour autant surcharger la page et en faisant le moins d’actions possibles.

Une bonne pratique est d’indiquer à l’utilisateur quels sont les champs obligatoires quelques soient les conditions afin de limiter les erreurs possibles en lui indiquant chaque champ par les traditionnelles asterisque (*). Cette bonne pratique ne résoudra par contre pas les règles métiers particulières. Exemples:

  • Le type de numéro de téléphone (mobile, bureau…) est requis si le téléphone est saisi
  • Le nom doit être en majuscule
  • La date de naissance doit être inférieure à la date du jour…
Noter toutes ces règles sur la page  est impossible car la lisibilité de celle-ci serait diminuée et le fait de l’indiquer à l’utilisateur ne l’empechera pas de ne pas remplir correctement le formulaire puisque celui-ci ne lira surement pas les indications. Il faut donc toujours contrôler ces règles lors de l’enregistrement, qui plus est pour une question évidente de sécurité, et trouver un nouveau moyen d’informer l’utilisateur des erreurs détectées dans le formulaire. Avec Scub Foundation, ce moyen s’appelle Contrôles d’Integrités (Integrity Control)

Que sont les contrôles d’intégrités?

Les contrôles d’intégrités sont toujours des règles métiers. La seule différence c’est que toutes les règles métiers en erreur lors de l’envoi d’un formulaire vont être retournées en même temps. En utilisant Scub Foundation, afin d’indiquer au client une erreur, les développeurs lèvent une BusinessException (erreur métier). Pour indiquer au client une liste d’erreurs, les développeurs peuvent maintenant également utiliser une IntegrityControlException.

Une IntegrityControlException a pour but de remonter toutes les erreurs qui peuvent être liées à un champ particulier du formulaire. Dans notre exemple précédent, les deux erreurs pouvaient respectivement être rattachées aux champs “prénom” et “date de naissance”. Pour les autres règles métiers, on utilise toujours une BusinessException. Pour donner un exemple,  si une formule de calcul utilise plusieurs champs du formulaire, l’erreur doit être globale et non liée à un champ.

Contrairement aux BusinessException qui ne peuvent transporter qu’un seul message d’erreur, l’IntegrityControlException doit pouvoir en transporter plusieurs et également indiquer à quel champ du formulaire ceux-ci sont attachés. Pour ce faire, les développeurs fournissent à l’exception un rapport définissant la liste des messages d’erreur et une clé permettant de le lier à un champ de la vue.

Un rapport complet

Le rapport contenu dans l’IntegrityControlException est un DTO permettant de transporter toutes les informations relatives aux champs du formulaire lors des contrôles. Il ne sert pas seulement à transporter les messages d’erreur, il peut également véhiculer des alertes ou encore des messages d’information. Cet article va se focaliser sur les messages d’erreur et laisser de côté les messages d’alerte ou d’information.

L’architecture du rapport est simple, il contient une simple map dont la clé correspond au champ en erreur et la valeur est un second DTO contenant la liste des messages d’erreur, d’alerte et d’information.

Revoir la façon d’écrire les règles métiers

Aujourd’hui chaque règle métier est gérée à grands coups de “if” combinés à la levée d’une exception métier:

if(StringUtils.isBlank(personne.getPrenom()) {
    throw new BusinessException(“Le prénom est requis”);
}

De ce fait, on se retrouve avec des dizaines et des dizaines de lignes de conditions et de levées d’exceptions au début de chacun de nos services traitant les formulaires. De plus, dans les tests unitaires, chaque règle métier va être testée de la même façon:

//test d’une personne sans prénom
try {
    personneService.creerOuModifierPersonne(personne);
    fail(“Le service aurait dû échouer, la personne n’a pas de prénom”);
} catch(BusinessException b) {
    assertEquals(“Le message d’erreur n’est pas celui attendu”, “Le prénom est requis”, b.getMessage());
}

C’est un travail plutôt répétitif et assez chronophage, surtout lorsque le nombre de règles est élevé ou que l’on doit valider des champs avec des expressions régulières ou parcourir des listes entières pour valider les sous DTO…

Les contrôles d’intégrités sont destinés à remplacer toutes ces lignes. Quasiment toutes les conditions effectuées en début de services peuvent être remplacées par une seule ligne. Et oui, même plus besoin d’écrire toutes ces conditions, même pour ajouter une nouvelle erreur au rapport. Dans 90% des cas, le remplissage du rapport va être fait automatiquement et pour ce faire, nous allons utiliser un framework de validation nommé Oval.

Oval

Oval est un framework Java ayant pour but de valider n’importe quel type d’objet. Il permet de valider les objets à la demande en faisant appel à des validateurs. Pour permettre cette validation, des annotations (@NotNull, @MaxLength…) pourront être posées sur les attributs ou les méthodes des classes. Oval peut comprendre certaines annotations EJB3 et JPA et sera donc capable de valider les objets de votre couche persistante. En plus d’également être compatible avec la programmation orientée aspect (AspectJ), Oval permet aussi d’exprimer vos contraintes en créant vos propres annotations ou en utilisant des langages de scripts comme Groovy, BeanShell et Javascript.

Voici un exemple pour que vous compreniez mieux à quoi sert Oval:

/**
* Objet pour transporter les
* informations d’une
* personne
**/
public class PersonneDto {
    @NotNull
    @NotEmpty
    @Length(max=32)
    private String nom;
 
    @NotNull
    @NotEmpty
    private String prenom;
...
}
//Validation d’un objet personne
Validator validator = new Validator();
 
// le nom et le prénom sont nulls
final PersonneDto pers = new PersonneDto();
 
// récupération des contraintes en erreur
List<ConstraintViolation>violations = validator.validate(pers);
if(violations.size()>0) {
    logger.error("Personne " + pers + " n’est pas valide.");
    throw new BussinessException(violations);
}

Le but d’oval va donc être de valider les DTO et de remplir automatiquement les rapports pour ensuite lever des IntegrityControlException en cas de problème. Pour faire cela de la façon la plus simple et la plus rapide possible pour le développeur, nous avons développé un validateur qui vous permettra de faire tout cela en une seule ligne au début de vos services.

***

Dans le prochain article sur la gestion des contrôles d’intégrités, nous verrons comment poser les contraintes sur les DTO et les règles à respecter pour toujours structurer au mieux les développements et ne pas aller à l’encontre des grands principes du développement SOA. Nous verrons également comment utiliser les validateurs mis à votre disposition et comment personnaliser et internationnaliser les messages d’erreurs qui vont être mis dans les rapports. Pour finir, nous allègerons significativement les tests unitaires (en nombre de lignes de code, pas en efficacité) grâce aux méthodes de tests fournies pour tester les erreurs remontées dans le rapport.

Accéder au second article de la trilogie >>