Architecture 3-tier, en Java, couche DAO

Architecture 3-tier, en Java, couche DAO - Java - Programmation

Marsh Posté le 03-07-2006 à 17:34:01    

Bonjour, je suis en train de concevoir une application en Java, pour laquelle j'ai décidé (aucune contrainte là dessus) d'utiliser une architecture 3-Tier. Mais j'ai quelques problèmes au niveau de la couche DAO (et surtout de différencier ce qui est dans la couche DAO et ce qui est dans ma couche métier). Voici comment j'ai procédé :  
 
Ma couche métier contient les objets métiers (par exemple un  utilisateur (son nom, mot de pase, id, des getters et des setters (mais pas sur tous les
attributs) et les services métiers (par exemple les services liés à l'utilisateur, tels que authentifier un utilisateur).
 
Afin de rendre indépendant ces objets de la manière de stocker des données, j'ai créé des "usines" (une par type d'objet metier) dans la couche d'accès aux données. Celles-ci sont chargées de créer les nouveaux objets, de les instancier à partir de la base de données, ... (j'ai essayé de  m'inspirer des EJB, que je ne peux pas utiliser faute de serveur adequat).
 
Ces usines présentent toutes une structure similaire avec :
une fonction pour créer un objet metier
une fonction pour le supprimer
une fonction pour le stocker dans la base
des finders, à partir de divers paramètres (Clé primaire, ou autre champ)
 
J'en arrive donc à me poser la question de créer une interface  Factory avec ces fonctions. Cependant, pour créer un utilisateur, il me faut un nom  et un mot de passe, mais pour créer un produit, il me faut un nom, un prix et une description.
 
Dois-je créer deux interfaces, du style :
 
BusinessObjectIfc
+String getPrimary Key()
+java.util.Properties getOtherFields()
+void setParam(String,Object)
 
FactoryIfc
+BusinessObjectIfc create(Properties)
+void delete(BusinessObjectIfc)
+void update(Entity)
+BusinessObjectIfc findByPrimaryKey(String)
+Collection findByOtherField(Properties)
 
De mon point de vue, ce système enlève de la lisibilité étant donné  que l'on ne saura pas par exemple que dans l'utilisateur,on peut acceder au nom d'utilisateur qui se situera à l'index "user" de l'object Properties renvoyé par getOtherFields, mais il me parrait plus logique de regrouper ces objets
présentant des structures similaires.  
 
Mais d'un autre côté, quand je regarde les EJB, je constate que  chacun possède sa propre interface avec ses fonctions create, ... et ses fonctions métier.
 
Je me demandais donc quelle solution choisir (je penche plutôt pour  la solution se rapprochant le plus des EJB, avec pas d'interface et pour chaque  "usine" ses fonctions, mais étant donné mes compétences ...), et s'il n'existait pas (sait-on jamais) une méthode en JAVA pour définir, en dehors de la doc, que tels et tels objets présentent tous une structure similaire ...  
 
Pourriez vous m'aider à éclairer ma lanterne (j'aimerais bien éviter les solutions dans le genre Spring+Hibernate et faire ça à la main une première fois histoire de comprendre un bon coup ...)
 
Par avance merci de votre réponse


Message édité par Titelf le 03-07-2006 à 17:38:25
Reply

Marsh Posté le 03-07-2006 à 17:34:01   

Reply

Marsh Posté le 04-07-2006 à 10:32:32    

Concernant le choix de l'une ou l'autre solution, tu pourrais commencer par celle qui consiste à proposer toutes les méthodes pour chaque "usine". Tu pourras factoriser le code de manière pragmatique une fois que tu auras bien implémenté ton DAO.
Et (mais je pense que c'est la première chose que tu as du faire, j'espère), va voir par là, la problématique est assez bien décrite :
 
http://java.sun.com/blueprints/cor [...] bject.html

Reply

Marsh Posté le 04-07-2006 à 12:07:34    

Merci pour ce lien, qui avait échapé a mes recherches ... à première vue, ça a l'air pas mal expliqué et devrait m'aider à faire avancer les choses.

Reply

Marsh Posté le 04-07-2006 à 13:50:07    

Titelf a écrit :

Merci pour ce lien, qui avait échapé a mes recherches ... à première vue, ça a l'air pas mal expliqué et devrait m'aider à faire avancer les choses.


 
Alors de manière plus générale, si tu veux de la documentation sur les Design Pattern appliqués à une architecture N-Tiers Java :
 
http://java.sun.com/blueprints/cor [...] index.html
 
Tu cliques sur une des boîtes et tu accèdes sur l'explication du Design Pattern.
 
Je tiens à préciser que ce sont des Pattern identifiés pour une architecture "classique" (pas de Spring avec son IOC par exemple) et que les framework ne sont pas présents (pas de Struts qui implémente automatiquement du MVC2 ...)  
 
a+

Reply

Marsh Posté le 06-07-2006 à 12:10:58    

C'est toujours pour la même application, mais plus dans la même couche (a vrai dire, c'est bien la le problème, je n'arrive pas à déterminer dans quelle couche placer le mécanisme d'authentification).
 
Je me demandais comment gérer l'authentification de manière à ce que l'utilisateur n'ai qu'a renter son login/mot de passe une seule fois. Il y a bien sur le mécanisme de sessions pour stocker tout ça, mais au niveau de la gestion de l'accès aux fonctions, ça se passe plutôt dans la couche métier ou dans la couche présentation ?  
 
Je pensais stocker dans la session (couche présentation donc si j'ai bien compris) le couple login/pass de l'utilisateur. Ma couche métier contiendrais une classe dont le rôle serait de gérer l'accès aux différentes fonctions métiers, en vérifiant à partir d'un couple login/mot de passe qu'on lui passerait que la fonction appelée peut l'être (en gros avec un truc du style AccessManager.callFunction(String login,String password, String funcName)), grâce à des permissions qui seraient gérées dans la base de données.  
 
Est-ce un bon choix ou n'ai-je rien compris ?
 
Cela me pose également un autre problème : comment faire en sorte que si mon utilisateur n'a pas accès a une fonctionnalité, il n'ait pas de lien vers cette fonctionnalité (en gros, si l'utilisateur n'a pas le droit de poster une news, qu'il n'ait pas le lien qui s'affiche vers poster une news). J'imagine qu'il faut ici, avec le système décrit plus haut, lister toutes les fonctions auquel l'utilisateur à accès et passer cette liste à la partie présentation qui la mettra en forme, non ?

Message cité 1 fois
Message édité par Titelf le 06-07-2006 à 12:13:56
Reply

Marsh Posté le 06-07-2006 à 13:42:52    

tu peux définir des groupes d'utilisateurs et faire un tag du genre :

Code :
  1. <securite:isGroup name="leGroupe">
  2.    <a href="...">blablabla</a>
  3. </securite:isGroupe>


Sinon, pour stocker ton utilisateur, les cookies, c'est pas mal, ça te permettrait de connaitre ton user, avec son id, et tu peux rechercher dans ton référentiel de sécurité pour voir à quel groupe il appartient...
 
tout ça tout ça quoi, enfin, c'set que des idées, d'autres me contre-dirons surement, avec des trucs mieux...


---------------
HFR - Mes sujets pour Chrome - Firefox - vérifie les nouveaux posts des topics suivis/favoris
Reply

Marsh Posté le 06-07-2006 à 15:58:19    

brisssou a écrit :

tu peux définir des groupes d'utilisateurs et faire un tag du genre :

Code :
  1. <securite:isGroup name="leGroupe">
  2.    <a href="...">blablabla</a>
  3. </securite:isGroupe>


Sinon, pour stocker ton utilisateur, les cookies, c'est pas mal, ça te permettrait de connaitre ton user, avec son id, et tu peux rechercher dans ton référentiel de sécurité pour voir à quel groupe il appartient...
 
tout ça tout ça quoi, enfin, c'set que des idées, d'autres me contre-dirons surement, avec des trucs mieux...


 
En tout cas moi je te contre-dis pas, concernant le tag et ça serait complémentaire à la gestion des autorisations que Titelf décrit.
 
En gros, le tag permettrait de créér des pages JSP en "dynamique", en fonction du rôle / profil de l'utilisateur connecté. Cela permettrait de de réaliser des menus avec des liens (l'exemple est pertinent avec le <a href="..."> bla bla</a> ) uniquement acessible par le rôle qui va bien.
 
Par contre, cela n'est ABSOLUMENT PAS suffisant ! eh oui, rien ne m'empêche, dans l'URL, de mettre le chemin pour accéder directement à une fonctionnalité, même si le lien n'a pas été intégré dans mon menu (mmh, suis je clair ?)
 
d'où mon post suivant ...

Reply

Marsh Posté le 06-07-2006 à 16:08:52    

Titelf a écrit :

C'est toujours pour la même application, mais plus dans la même couche (a vrai dire, c'est bien la le problème, je n'arrive pas à déterminer dans quelle couche placer le mécanisme d'authentification).
 
Je me demandais comment gérer l'authentification de manière à ce que l'utilisateur n'ai qu'a renter son login/mot de passe une seule fois. Il y a bien sur le mécanisme de sessions pour stocker tout ça, mais au niveau de la gestion de l'accès aux fonctions, ça se passe plutôt dans la couche métier ou dans la couche présentation ?  
 
Je pensais stocker dans la session (couche présentation donc si j'ai bien compris) le couple login/pass de l'utilisateur. Ma couche métier contiendrais une classe dont le rôle serait de gérer l'accès aux différentes fonctions métiers, en vérifiant à partir d'un couple login/mot de passe qu'on lui passerait que la fonction appelée peut l'être (en gros avec un truc du style AccessManager.callFunction(String login,String password, String funcName)), grâce à des permissions qui seraient gérées dans la base de données.  
 
Est-ce un bon choix ou n'ai-je rien compris ?
 
Cela me pose également un autre problème : comment faire en sorte que si mon utilisateur n'a pas accès a une fonctionnalité, il n'ait pas de lien vers cette fonctionnalité (en gros, si l'utilisateur n'a pas le droit de poster une news, qu'il n'ait pas le lien qui s'affiche vers poster une news). J'imagine qu'il faut ici, avec le système décrit plus haut, lister toutes les fonctions auquel l'utilisateur à accès et passer cette liste à la partie présentation qui la mettra en forme, non ?


 
Pour commencer avec la sécurité applicative, le maître mot est centralisation (ou factorisation, unique point d'accès aussi, ...).
 
"A la main"
Ce qui est beaucoup utilisé en Java pour l'authentification est le filtre de servlet. Il traite toutes les requêtes HTTP en entrée comme en sortie.
En entrée, il peut par exemple vérifier qu'il existe bien un objet (objet User par exemple) en session. Si oui, il laisse passer, sinon il redirige vers la page de login.
Cette page de login (formulaire) peut être couplée avec une classe action qui va stocker un objet User en session si l'authentification réussit (la boucle est bouclée)
 
Concernant l'habilitation maintenant, si tu pars sur un framework tiers de présentation (Struts par ex), la bonne pratique est "d'intercaler" une classe dont héritent toutes tes classes actions Struts et qui hérite elle même de la classe BaseAction de Struts. Cela voudra dire qu'à chaque fois qu'une classe action est appelée, elle passe obligatoirement par cette classe intermédiaire qui pourra par exemple traiter la gestion d'habilitation (l'exemple AccessManager.callFunction(String login,String password, String funcName) est bon même si une fois l'authentification réussie on ne trimbale pas le login et password dans l'appli mais plutôt le profil associé) donc plutôt un AccessManager.callFunction(String profil, String funcName) et qui te renvoie un booléen ...
 
"De manière déclarative"
Il est possible, de manière déclarative et grâce aux spec SUN et à leur implémentation (JAAS) de déclarer tes ressources protégées. (Par contre je suis peusec dessus, il me semble que c'est dans le web.xml qu'on déclare les ressources par URL protégées et quels sont les profils qui y ont accès). C'est ensuite le conteneur qui se charge de la sécurité ..
 
"via des frameworks tiers"
va voir du côté de Acegi security ... mais ça s'utilise apparemment avec le framework Spring
 
je reviendrai sur le topic de temps en temps, je me suis pas trop relu et j'ai peur de pas avoir été trop clair ...  :whistle:  
 
a+

Reply

Marsh Posté le 06-07-2006 à 16:11:28    

brisssou a écrit :

tu peux définir des groupes d'utilisateurs et faire un tag du genre :

Code :
  1. <securite:isGroup name="leGroupe">
  2.    <a href="...">blablabla</a>
  3. </securite:isGroupe>


Sinon, pour stocker ton utilisateur, les cookies, c'est pas mal, ça te permettrait de connaitre ton user, avec son id, et tu peux rechercher dans ton référentiel de sécurité pour voir à quel groupe il appartient...
 
tout ça tout ça quoi, enfin, c'set que des idées, d'autres me contre-dirons surement, avec des trucs mieux...


 
d'ailleurs, si je m'abuse, Struts propose un tag comme ça qui va vérifier en session applicative quel est le profil stocké...

Reply

Marsh Posté le 06-07-2006 à 17:32:52    

Pour l'authentification et l'habilitation, je pense avoir compris le truc (apparament, j'étais pas trop loin du compte...).  
 
Mais pour les liens, est-ce que la solution peut fonctionner si on ne connait pas les groupes à l'avance (en gros il pourrait y avoir autant de groupes qu'une base de données peut en contenit (ça fait un gros tas)), avec, pour certaines fonctionnalités, le fait que plusieurs groupes peuvent y accéder ?  
 
Ou est-ce que pour un utilisateur donné, la classe chargée de l'habilitation ne pourrait pas donner la liste des fonctions accessibles (leurs libélés et l'URL par exemple), dans lequel la couche présentation ferait le tri pour n'afficher que ce dont elle a besoin ? Ca me parait, par exemple, s'il n'y a qu'un seul lien sur la page, demander beaucoup de données pour en afficher peu. Une autre solution que j'ai envisagé, serait que ma couche présentation demande à la couche métier si tel lien peut-être affiché pour l'utilisateur actuellement logué ... ce serait mieux ?

Reply

Marsh Posté le 06-07-2006 à 17:32:52   

Reply

Marsh Posté le 07-07-2006 à 09:58:39    

Titelf a écrit :

Pour l'authentification et l'habilitation, je pense avoir compris le truc (apparament, j'étais pas trop loin du compte...).  
 
Mais pour les liens, est-ce que la solution peut fonctionner si on ne connait pas les groupes à l'avance (en gros il pourrait y avoir autant de groupes qu'une base de données peut en contenit (ça fait un gros tas)), avec, pour certaines fonctionnalités, le fait que plusieurs groupes peuvent y accéder ?  
 
Ou est-ce que pour un utilisateur donné, la classe chargée de l'habilitation ne pourrait pas donner la liste des fonctions accessibles (leurs libélés et l'URL par exemple), dans lequel la couche présentation ferait le tri pour n'afficher que ce dont elle a besoin ? Ca me parait, par exemple, s'il n'y a qu'un seul lien sur la page, demander beaucoup de données pour en afficher peu. Une autre solution que j'ai envisagé, serait que ma couche présentation demande à la couche métier si tel lien peut-être affiché pour l'utilisateur actuellement logué ... ce serait mieux ?


 
Si on connait pas les groupes à l'avance, une solution serait de réaliser une habilitation stockée en base de données avec une équivalence profil / liste de fonctionnalités autorisées.
Chaque page accédée (quand je parle de "page", je sous-entends une servlet (action Struts par exemple)) la méthode d'habilitation est appelée. Cette dernière récupère le profil en session puis va récupérer l'ensemble des fonctionnalités auxquelles il a droit en base (on peut ensuite imaginer un système de cache pour éviter d'aller requêter en base à chaque fois .. ).Là on aurait du full-dynamique dans l'habilitation. Si on connaît par avance les différents groupes, les rôles (admin, user, superuser, ...) de chaque groupe et les fonctionnalités accédées, on peut stocker cette correspondance dans un fichier de propriétés (ou, je le rappelle, faire de la sécurité de manière déclarative : on déclare dans le fichier "web.xml" quelles sont les ressources protégées et quels groupes a le droit d'accéder à quoi).
 
Pour la solution de la construction du menu en dynamique, la solution du tag me paraît très bien. (en gros le tag, inséré dans une JSP cette fois va tester le profil stocké en session. Si le profil correspond au test, il affiche ce qui se trouve entre les tags) .. ça ne marche évidemment que si on connaît, par avance ts les profils de l'appli.
Ensuite on peut prendre comme autre solution un objet Java classique qui va construire le menu en dynamique en fonction du profil connecté. Mais que la couche métier "remonte" à la couche présentation toutes les URL possibles me paraît pas très "secure".  :o  
 
Mais déjà, une belle authentification avec un joli filtre de servlet (il doit y avoir des millairds de tutos dessus sur le net) avec le stockage d'un objet (profil, user ...) en session pouvant être réutilisé ensuite ds toute l'application (affichage d'infos personnalisé, affichage d'un menu spécifique, habilitation sur les fonctionnalités -> toujours penser qu'une URL peut être accéder autrement que par un menu construit en dynamique ! en tapant tout simplement la bonne URL ds le navigateur ... )
 
En espérant avoir été clair ...  :hello:

Reply

Marsh Posté le 10-07-2006 à 11:57:02    

Merci pour les précédentes réponses.
 
J'ai un nouveau problème, toujours sur la même application, toujours sur l'accès aux données.  
 
J'ai un objet métier utilisateur, stockant login/mot de passe et Id de l'utilisateur.
A coté, j'ai un objet métier news stockant une id, un titre, un contenu, une date (jusque là des types simples), mais il me faut aussi avoir accès à l'utilisateur. Pour celà, j'envisage deux solutions : stocker directement un objet de type utilisateur (de toutes façon, il y a de grande chances qu'il me faille le manipuler à un moment ou à un autre, alors autant le stocker), ou alors stocker l'id de mon utilisateur (c'est ce que je stocke dans ma base de données).
 
Je me demandais donc si l'une des solutions était meilleure que les autres, la première demandant pas mal de mémoire tandis que la seconde demande plus d'accès à la base de données ? Je penchait pour la seconde, plus simple à mon gout ... mais est-ce que simple rime avec performant ?

Reply

Marsh Posté le 10-07-2006 à 14:48:56    

Titelf a écrit :

Merci pour les précédentes réponses.
 
J'ai un nouveau problème, toujours sur la même application, toujours sur l'accès aux données.  
 
J'ai un objet métier utilisateur, stockant login/mot de passe et Id de l'utilisateur.
A coté, j'ai un objet métier news stockant une id, un titre, un contenu, une date (jusque là des types simples), mais il me faut aussi avoir accès à l'utilisateur. Pour celà, j'envisage deux solutions : stocker directement un objet de type utilisateur (de toutes façon, il y a de grande chances qu'il me faille le manipuler à un moment ou à un autre, alors autant le stocker), ou alors stocker l'id de mon utilisateur (c'est ce que je stocke dans ma base de données).
 
Je me demandais donc si l'une des solutions était meilleure que les autres, la première demandant pas mal de mémoire tandis que la seconde demande plus d'accès à la base de données ? Je penchait pour la seconde, plus simple à mon gout ... mais est-ce que simple rime avec performant ?


 
Si j'ai bien compris, la question est "dois je stocker en base un objet entier utilisateur ou uniquement l'id" ? c'est ça ? non en fait je crois que j'ai pas saisi la question ...  :whistle:  
 
Je vais essayer de répondre, de toutes façons, tu devras certainement mettre un objet utilisateur (ou en tout cas profil) dans le contexte de session de ton appli web. Et normalement, ce objet est récupéré à la connexion par la servlet qui gère ton authentification qui va récupérer les infos .. en base de données justement. Donc oui, tu auras une table "User" qui aura certainement un Id en clef primaire puis un nom, prénom, etc ... (et pas uniquement l'id).
 
Si ta question était : pourquoi ne pas remonter le moins d'infos possibles de la base de données pour des raisons de perf (remonter qu'une info plutôt que plusieurs), la réponse est que la différence sera infinitésimale et que ce sera pas là que tu perdras du temps (enfin bon tout est relatif, je parle de la différence entre la récupération en lecture d'un ou trois champs). Là où tu perdras le plus de temps, c'est à l'ouverture / fermeture de connexion, temps réseau, etc ...  
Dans ce cadre là, les solutions, pour les performances aux accès en base passent, côté Java, à l'utilisation de DataSource ou des pools de connexion et la gestion d'un cache (pour éviter de redemander 2 fois la même chose en base ... ). Et c'est plutôt là qu'il faudra axer ses efforts (mise en place d'un DAO + Pool de connexion + un cache si besoin est ... avec ouverture et fermeture propre, tu dois avoir pas mal d'exemples sur le net)
 
Côté Base, tu as des solutions propriétaires comme les procédures stockées ...
 
ai je répondu ou pas ?  :D  

Reply

Marsh Posté le 10-07-2006 à 17:09:28    

Tu as répondu  ;) , merci.
 
C'est plutôt la deuxième question qui me préoccupait. Si j'ai bien compris, je vais devoir mettre en place un certain nombre de connexions, qui seront actives en même temps, pour pouvoir accélerer les requêtes, et stocker, dans une structure de données adaptée, les objets déja instanciés. Lorsque je chercherais un objet, il me faudra donc, avant de demander à ma base, regarder s'il n'est pas déja parmi ceux instanciés.
 
Je vois pas trop, par contre, en quoi les pocédures stockéees pourraient m'aider. En remontant directement l'utilisateur et la news, ce qui éviterait deux accès à la base ?

Reply

Marsh Posté le 10-07-2006 à 21:49:30    

Titelf a écrit :

Tu as répondu  ;) , merci.
 
C'est plutôt la deuxième question qui me préoccupait. Si j'ai bien compris, je vais devoir mettre en place un certain nombre de connexions, qui seront actives en même temps, pour pouvoir accélerer les requêtes, et stocker, dans une structure de données adaptée, les objets déja instanciés. Lorsque je chercherais un objet, il me faudra donc, avant de demander à ma base, regarder s'il n'est pas déja parmi ceux instanciés.
 
Je vois pas trop, par contre, en quoi les pocédures stockéees pourraient m'aider. En remontant directement l'utilisateur et la news, ce qui éviterait deux accès à la base ?


 
Tu as des requêtes qui parfois peuvent se révéler très lourdes dans des schémas complexes (inclusions d'inclusions de tables, etc ...) et il y avait un discours qui tendait à dire : Java / J2EE, c'est beau, c'est neuf, on est capable de faire abstraction de la base de données avec les bonnes pratiques (Design Pattern DAO, frameworks de mapping O/R) alors pour réaliser une application qui soit complètement indépendante de la base de données, on fait TOUT le métier (requêtes, etc ...) côté serveur d'applications. On assistait alors à des machines qui tournaient à 100% du processeur pour les serveur d'applis et du 2 ou 3% pour la base de données qui ne faisait rien.
Dans la réalité, un système d'information ne change pas du jour au lendemain de BD, donc autant profiter des atouts de la base !!! d'où les procédures stockées pour faire des requêtes complexes, mettre un peu de métier côté base quoi ... Bref, pour ton appli, ça servira à rien !  ;)  
 
Sinon, dernière chose, tu peux faire des accès en base via du JDBC (tu contrôles des ouvertures / fermeture de connexion, ton cache, ...) et la solution est de passer par une DataSource (pool de connexion fourni par le serveur d'applis).
 
Mais il existe des frameworks qui te proposent des solutions de mapping O/R (Objet / Relationnel) et qui te masquent toute la complexité (relative ...) des requêtes en base et qui te fournissent des services par défaut (transactionnalité, pool de connexion, etc ... ). Et pour débuter (et pas que pour débuter d'ailleurs ...) je peux te conseiller d'aller voir Hibernate ...
 
a+ pour la prochaine question ...  :D

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed