Préambule

Avant tout développement d'une application WEB, il est important de réfléchir à son architecture. A mon sens une architecture bien conçue est d'une part une architecture robuste qui respecte les patterns standards et d'autre part une architecure qui reste simple en termes de développement. Ayant eu une petite expérience sur les EJB 2.0, cette architecture est certes robuste et suit les patterns standards, mais sa mise en place reste pénible.

L'architecture ne peut pas être conçue sans connaître les fonctionnalités de l'application à réaliser. Par exemple, il est important de se poser les questions sur les fonctionnalités, comme la pagination, le tri, la complexité des critères de recherches dans les formulaires de recherches... Voir la section fonctionnalites pour connaître les fonctionnalités utilisés dans gestCV (qui se retrouvent dans la plupart des applications WEB).

Il est important, lors de la mise en place d'une architecture de ne pas "réinventer la roue" mais de s'appuyer sur des frameworks (cadre de développement) robustes, simples et qui ont fait leur preuve.

Dans le monde J2EE, il existe de nombreux frameworks disponibles. L'architecture proposée dans le projet GestCV tentera de respecter au mieux les patterns existant, tout en restant simple en terme de développement. Plus l'architecture restera simple, moins il y aura de développement à effectuer et par conséquent moins de bugs.

GestCV s'appuie sur plusieurs frameworks qui aujourd'hui ont fait leur preuve, et sont toujours en pleine effervescence :

  • Struts pour le cadre de développement de l'application de GestCV.
  • Spring pour la gestion des accès à la base de données (connection et transaction).
  • Hibernate pour gérer la persistance des objets dans une base de données relationnelle, autrement dit récupérer ou mettre à jour les enregistrements de la base de données.

L'objectif de ce site a pour but de décrire l'utilisation de ces 3 frameworks combinés. Il tentera aussi de décrire les mécanismes importants utilisés dans l'application. Ces mécanismes ont pour but de simplifier le développement. Tout au long de ce site, je tenterai d'expliquer la démarche de ma réflexion, les choix de conception, et les questions que je me suis posées lors de la réalisation de GestCV.

Architecture

Voici un schéma global de l'architecture de GestCV :

GestCV est basée sur Struts, framework MVC (Modéle Vue Contrôle) :

  • Struts distingue un contrôleur principal (ActionServlet), qui aiguille les requêtes reçues du client vers des sous contrôleurs (Action Struts) qui vont alors effectuer le traitement correspondant. Le contrôleur principal qui est assuré par la servlet Struts ActionServlet est ainsi le point d'entrée de toute requête HTTP constituée d'url se terminant par l'extension .do (voir configuration de Struts dans le fichier web.xml). La servlet appelle ensuite le Request Processor qui entre autre instancie et appelle la classe Action correspondant à l'url demandé.
  • Le composant Modèle correspond aux traitements métiers d'une Application WEB. Struts ne fournit aucune implémentation pour le modèle. GestCV implémente le modèle suivant le pattern Service/DAO :
    • les classes Actions font appel à la couche Service pour appeler les processus métier de l'application GestCV. Les actions manipulant des Formulaires Struts, celles-ci communiquent avec la couche Service par l'intermédiaire d'objet DTO (Data Transfert Object).
    • La couche service qui a pour rôle de gérer le métier de GestCV, appelle les DAO (Data Access Object) qui accèdent aux données de la base de données par l'intermédiaire d'objet de type Bean (en EJB, on parle d'Entity Bean). Le découpage DTO/Bean peut paraître à première vue superflu, car les données DTO et Bean sont identiques. Ce choix de conception sera détaillé plus en détail dans la section Form, DTO et Bean.

    A la fin du traitement d'une Action Struts, après avoir peuplé le formulaire Struts avec les DTO retournés par les Services, et/ou enregistré dans la request les listes de DTO à afficher, le composant vue est appelé (redirection vers une JSP).

  • Vue : Les JSP utilisent les données des Formulaires Struts et parfois les DTO (dans le cas d'affichage d'une liste) provenant de la partie modèle pour afficher le rendu final en HTML. Dans le modèle MVC, il ne doit pas avoir d'appel aux processus métier dans les JSP.

Le pattern Service/DAO sera implémenté par l'utilisation de deux frameworks :

  • Les Services qui font appels aux DAO seront implémentés à l'aide de Spring, qui permet entre autre de simplifier la gestion des connexions à une base de données. Voir la section Spring pour plus d'information.
  • Les DAO seront implementées en Hibernate, qui permet de simplifier les accès à la base de données (recherche, mise à jour de la base de donnée,...). Voir la section Hibernate pour plus d'information.

Form, DTO et Bean

Dans une application WEB, la Vue, autrement dit la page HTML, doit afficher les informations provenant de la base de données et/ou doit mettre à jour les données de la base par l'intermédiare de fomulaire HTML. Les données postées par le formulaire sont des chaînes de caractères String et les données de la base sont des types plus complexes (String, Integer, Date,...).

Une conversion de type de données est nécessaire à moment ou un autre, pour faire communiquer les données de la vue avec la base de données.

La question qui vient alors l'esprit est quelle est la meilleure architecture qui permet de gérer la communication entre la vue et la base de données ? La réponse selon moi est aucune. Il existe de nombreux articles traitant de ce sujet, mais aucun me paraît l'unique solution à mettre en place.

Selon la couche Action, Service et DAO, GestCV manipule trois types d'objets : les Bean, les Form et les DTO.

Bean

Les objets Bean sont les objets persistants de l'application GestCV (communicant avec la base de données). Ces objets permettent de :

  • récupérer les informations de la base de données.
  • mettre à jour la base de données.

GestCV utilisant Hibernate comme couche de persistance, ceux-ci sont surveillés par la session Hibernate. Autrement dit la modification (appel d'un setter) d'un de ces objets engendrera une modification dans la base de données. L'appel de certaines méthodes (initialisés en mode lazy) d'un objet Bean, engendrera la récupération des données de la base.

Form

Dans une application Struts, le formulaire est représenté par une classe qui doit hériter de la classe de base ActionForm (ou autres classes dérivées de ActionForm). La classe représentant un formulaire doit implémenter tous les getter/setter des champs constituant le formulaire.

Les formulaires de GestCV seront constitués de getter/setter de type simple java.lang.String uniquement. Voir la section Formulaire Struts pour connaître la raison de ce choix et avoir plus de détail sur l'implémentation des formulaires de gestCV.

DTO

Les objets DTO (Data Transfert Object) ont pour but d'assurer la communication entre les données de la base (Bean) et les formulaires (Form). Cette communication s'effectue dans les deux sens :

  • Bean -> DTO -> Form, dans le cas où le formulaire doit être alimenté par les données de la base de données. Dans ce cas-ci, la DTO récupère les informations d'un ou plusieurs Bean, et le formulaire s'alimente avec les informations de cette première. La DTO doit contenir les données que la vue a besoin d'afficher, ce qui nécéssite parfois un assemblage de plusieurs Bean. En effet un Bean a une structure qui correspond à une table, ou a un ensemble de table (graphes d'objets). Cette phase d'assemblage est assurée par la couche Service.
  • Form -> DTO -> Bean, dans le cas où la base de données doit être mise à jour par les données provenant du formulaire. La transformation du formulaire en DTO permet de convertir les données String du formulaire en types plus complexes. Cette conversion de type de données est assurée par la couche Action Struts. La couche Service transforme ensuite la DTO en Bean où plusieurs bean (dans le cas où plusieurs tables doivent être mises à jour) et fait appel à la couche DAO implémentée en Hibernate.

L'architecture Form/DTO/Bean présentée, celle-ci peut être maintenant critiquée. Voici les questions que je me suis posé face à cette architecture :

  • pourquoi ne pas utiliser les Bean en tant que DTO ? Les Bean et DTO semble être identique ? De plus Hibernate permet de charger de charger des données à la demande (mode lazy) pour ansi obtenir un graphe d'objet. Un très bon article parlant du mécanisme Objets attachés et DTO détachés critique l'architecture DTO/Bean. Cette technique fonctionne très bien, mais celle-ci peut devenir dangereuse si on oublie de détacher l'objet, ce qui pourrait engendrer des modifications de la base sans le vouloir. Pour des raisons de sécurités, GestCV copie les données des Bean dans la DTO, pour s'assurer que l'objet retourné dans la Vue ne soit plus transactionnel.

    Le découpage DTO et bean, permet aussi de retourner des DTO complexes qui peuvent être construites à partir de plusieurs Bean.

  • pourquoi ne pas fusionner les Form et les DTO ? J'ai pu constater que certaine architecture utilisait leur DTO en tant que Form. Ceci implique que la DTO, ait des getter de type String. (voir section Formulaire Struts). Personnelement je préfère que les getter d'une DTO soit de type plus complexes pour pouvoir effectuer des opérations métier sur la DTO elle-même (ex : calcul d'un âge à partir de la date de naissance java.util.Date ).

    La fusion DTO/Form engendre de plus un très fort couplage a Struts. Ce choix de conception ne permettra pas par exemple d'utiliser les services dans une autre application qui ne serait pas implémentée en Struts.

Fonctionnalites

Tri & Pagination

Le tri et la pagination sur des listes de données sont des fonctionnalités qui se retrouvent souvent dans une application WEB. Il existe deux grands principes d'implémentation de ses fonctionnalités :

  • le tri/pagination implémenté en JAVA. Le principe de cette implémentation est de charger toutes les données de la base dans une collection JAVA puis de trier et de paginer cette liste à l'aide de méthodes JAVA. Généralement cette liste est mise en session utilisateur. La plupart des composants comme struts-layout, DisplayTag 1.0 fonctionnent sur ce principe. Le problème de cette solution dépend de la volumétrie des données. En effet les performances de tri/pagination peuvent devenir catastrophiques, lorsque la liste de données devient conséquente. Pire, il peut arriver que la liste soit tellement conséquentes, qu'il est impossible de charger la liste faute de place en mémoire.
  • le tri/pagination au niveau base de données. Le principe est de trier/paginer par l'intermédiaire de requête SQL. En ce qui concerne le tri, il suffit d'ajouter la commande ORDERBY dans la requête SQL de sélection de la liste. Pour la pagination, ceci dépend de la base de données utilisée. La plupart des bases sont capables de paginer à l'aide de commande SQL. Si la base n'est pas capable d'effectuer la pagination, il est possible de parcourir le ResultSet retourné par la requête de sélection et de n'alimenter sa liste qu'avec les données qui doivent être affichées.

Suite à mon expérience, je préfère le tri/pagination aux niveau bases. Je trouve que beaucoup de patterns sous-estiment les capacités de la base de données qui n'est pas seulement un containeur de données.

GestCV en termes de volumétrie ne parait pas très conséquent, cependant, l'application implémentera la pagination/tri au niveau base de données. En effet DisplayTag 1.1 permet aujourd'hui d'utiliser sa propre gestion de pagination en implémentant l'interface PaginatedList. GestCV implémentera :

  • Le Tri & pagination aux niveaux Hibernate à l'aide de la classe HibernatePage pour trier/paginer au niveau base de données.
  • Le Tri & pagination avec DisplayTag 1.1, qui utilisera les informations de la classe HibernatePage pour afficher la liste retournée par l'objet HibernatePage.

AJAX

L'accueil de GestCV affiche la liste des CV disponibles. Plusieurs critères de recherche d'un CV dont les compétences le nom, le prénom du collaborateur sont disponibles. Pour aider l'utilisateur dans sa recherche, un assistant d'aide (autocomplétion) s'affiche en temps réel avec les données de la base correspondant aux caractères saisis. Cette fonctionalité utilise le principe d'AJAX.

Ce composant n'a pas été developé, il s'appuie sur la librairie AjaxTags, qui permet de gérer des composant AJAX. Vous trouverez plus d'information dans la section AJAX.

Les classes de Base

Toutes les classes utilisées dans GestCV, que ce soit les classes Services, DAO, Criteria, DTO, Bean, ValidatorActionForm, DispatchAction,... héritent toutes d'une classe de base (BaseService, BaseCriteria, BaseDTO,...). Je conseille d'en faire autant, lorsque vous mettez en place un nouveau type de données. Même si votre classe de base ne contient aucune méthode, aucune propriéte lorsque vous mettez en place votre type de données, une application WEB évolue dans le temps lors de l'ajout de nouvelles fonctionnalités. Il se peut que votre type de données évolue aussi, et qu'il soit aussi susceptible de gérer une méthode, une propriété en commun.