JEE Avec Netbeans

341
Introduction à Java EE 5 avec Netbeans 6.8 et le serveur d'applications Glassfish V3 serge.tahe at istia.univ-angers.fr juin 2010 http://tahe.developpez.com/java/javaee 1/341

Transcript of JEE Avec Netbeans

Introduction Java EE 5 avec Netbeans 6.8 et le serveur d'applications Glassfish V3

serge.tahe at istia.univ-angers.fr juin 2010

http://tahe.developpez.com/java/javaee

1/341

INTRODUCTIONCe document reprend un prcdent document crit en 2007 et intitul "Introduction Java EE avec Netbeans 5.5.1". Celui-ci intitul "Introduction Java EE 5 avec Netbeans 6.8 et le serveur Glassfish v3" adapte le document prcdent Netbeans 6.8. Les copies d'cran ne convenaient plus et Netbeans 6.8 amne avec lui des assistants qui n'existaient pas avec Netbean 5.5.1. En-dehors du changement d'IDE, les deux documents sont semblables. Java EE signifie Java Enterprise Edition. J2EE (Java 2 Enterprise Edition) tait le terme prcdent. J2EE dsigne les technologies Java utilises pour crer des applications d'entreprise avec le JDK 1.4 ou antrieur. En mme temps que le JDK 1.5 amenait de nombreuses nouveauts dans le langage Java, Sun introduisait de nouvelles technologies s'appuyant sur ce langage amlior afin de remdier des lacunes de ces mmes technologies dans J2EE. Le terme Java EE 5 a alors t utilis pour dsigner l'ensemble des technologies qui concourent crer une application d'entreprise avec la plate-forme Java. Au moment de la mise jour de ce document, la dernire version de Java EE est Java EE 6. Les livres d'Antonio Goncalves :

Java EE 5 aux ditions Eyrolles Beginning Java EE 6 Platform with Glassfish 3 aux ditions Apress

sont d'excellents livres pour dcouvrir les technologies de Java EE 5 et Java EE 6. Toutes les technologies importantes de Java EE y sont passes en revue dans le contexte d'tudes de cas ralistes. L'auteur a un site [http://www.antoniogoncalves.org] que le lecteur est invit visiter. Le document prsent tudie certaines des technologies de Java EE 5. Nous y crons une application basique trois couches [prsentation, mtier, accs aux donnes] dcline en plusieurs versions : Une application web avec les technologies suivantes : JavaServer Faces : pour la couche web Ejb3 ou Spring : pour la couche mtier Ejb3 ou Spring, Jpa/Hibernate, Jpa/EclipseLink : pour crer diffrentes couches d'accs aux donnes Une application client / serveur avec les technologies suivantes : Swing : pour la couche graphique cliente avec un support Spring Ejb3 ou service web : pour la couche serveur Certaines technologies Java EE ne sont pas prsentes telles les MDB (Message Driven Bean) ou les Ejb3 stateful. Pour les dcouvrir, on lira les livres d'Antonio Goncalves. Il existe d'autres technologies Open Source disponibles pour crer des applications trois couches. Une tandem trs populaire est Spring (http://www.springframework.org/) / Hibernate (http://www.hibernate.org/). Afin de permettre au lecteur de comparer les technologies Ejb3 et Spring, l'application prcdente a des versions o Spring remplace les Ejb3. Le document a deux parties bien distinctes :

la premire partie est un TD utilis en 5ime anne de l'cole d'ingnieurs ISTIA de l'universit d'Angers [http://www.istia.univ-angers.fr]. Un TD est un Travail Dirig. Ce TD dcrit l'application construire, les technologies Java utiliser, les endroits o trouver de l'information. La solution propose est trs cadre. Le TD pose des questions dont il ne donne pas les rponses. C'est l'tudiant de les trouver. la seconde partie est un cours sur JSF (JavaServer Faces). Il sert d'appui pour crire la couche web de l'application exemple.

L'apprentissage Java EE propos ici ncessite un investissement du lecteur estim entre 50 et 100 heures. Le document contient beaucoup de code rendant possible le copier / coller. Par ailleurs, tous les projets Netbeans sont dcrits dans le dtail. Globalement, le document donne les squelettes des solutions et il est demand l'tudiant d'en donner certains dtails. Le document peut tre utile mme quelqu'un ne pouvant ou ne voulant pas s'investir autant. On peut s'intresser uniquement aux architectures dcrites et dlaisser la partie code qui fait l'objet des questions. Pour dvelopper et excuter l'application, nous utilisons l'IDE Netbeans 6.8. Netbeans est un produit assez lourd : prvoir 1 Go de Ram pour travailler confortablement. On peut le tlcharger l'url [http://www.netbeans.org/].

http://tahe.developpez.com/java/javaee

2/341

Le document fait rfrence aux cours suivants : 1. 2. Persistance Java 5 par la pratique : [http://tahe.developpez.com/java/jpa] - donne les outils pour construire la couche d'accs aux donnes avec Jpa (Java Persistence Api) Introduction au langage Java [http://tahe.developpez.com/java/cours] - pour les dbutants

Ces supports de cours sont par la suite rfrencs [ref1] et [ref2]. Serge Tah, juin 2010.

http://tahe.developpez.com/java/javaee

3/341

1 Architecture d'une application Java en couchesUne application java est souvent dcoupe en couches chacune ayant un rle bien dfini. Considrons une architecture courante, celle trois couches :

utilisateur

Couche interface utilisateur [ui] 1

Couche mtier [metier] 2

Couche d'accs aux donnes [dao] 3

Donnes

la couche [1], appele ici [ui] (User Interface) est la couche qui dialogue avec l'utilisateur, via une interface graphique Swing, une interface console ou une interface web. Elle a pour rle de fournir des donnes provenant de l'utilisateur la couche [2] ou bien de prsenter l'utilisateur des donnes fournies par la couche [2]. la couche [2], appele ici [metier] est la couche qui applique les rgles dites mtier, c.a.d. la logique spcifique de l'application, sans se proccuper de savoir d'o viennent les donnes qu'on lui donne, ni o vont les rsultats qu'elle produit. la couche [3], appele ici [dao] (Data Access Object) est la couche qui fournit la couche [2] des donnes pr-enregistres (fichiers, bases de donnes, ...) et qui enregistre certains des rsultats fournis par la couche [2].

Il existe diffrentes possibilits pour implmenter la couche [dao]. Examinons-en quelques-unes :

utilisateur

Couche ui [ui] 1

Couche mtier [metier] 2

Couche d'accs aux donnes [dao] 3

Couche [JDBC]

Base de Donnes

La couche [JDBC] ci-dessus est la couche standard utilise en Java pour accder des bases de donnes. Elle isole la couche [dao] du SGBD qui gre la base de donnes. On peut thoriquement changer de SGBD sans changer le code de la couche [dao]. Malgr cet avantage, l'API JDBC prsente certains inconvnients : toutes les oprations sur le SGBD sont susceptibles de lancer l'exception contrle (checked) SQLException. Ceci oblige le code appelant (la couche [dao] ici) les entourer par des try / catch rendant ainsi le code assez lourd. la couche [dao] n'est pas compltement insensible au SGBD. Ceux-ci ont par exemple des mthodes propritaires quant la gnration automatique de valeurs de cls primaires que la couche [dao] ne peut ignorer. Ainsi lors de l'insertion d'un enregistrement : avec Oracle, la couche [dao] doit d'abord obtenir une valeur pour la cl primaire de l'enregistrement puis insrer celui-ci. avec SQL Server, la couche [dao] insre l'enregistrement qui se voit donner automatiquement une valeur de cl primaire par le SGBD, valeur rendue la couche [dao]. Ces diffrences peuvent tre gommes via l'utilisation de procdures stockes. Dans l'exemple prcdent, la couche [dao] appellera une procdure stocke dans Oracle ou SQL Server qui prendra en compte les particularits du SGBD. Celles-ci seront caches la couche [dao]. Nanmoins, si changer de SGBD n'impliquera pas de rcrire la couche [dao], cela implique quand mme de rcrire les procdures stockes. Cela peut ne pas tre considr comme rdhibitoire. De multiples efforts ont t faits pour isoler la couche [dao] des aspects propritaires des SGBD. Une solution qui a eu un vrai succs dans ce domaine ces dernires annes, est celle d'Hibernate :

Couche d'accs aux donnes [dao] 3

4 Objets image de la BD

Couche [Hibernate] 5

Couche [JDBC] 6

Base de Donnes 7

http://tahe.developpez.com/java/javaee

4/341

La couche [Hibernate] vient se placer entre la couche [dao] crite par le dveloppeur et la couche [Jdbc]. Hibernate est un ORM (Object Relational Mapping), un outil qui fait le pont entre le monde relationnel des bases de donnes et celui des objets manipuls par Java. Le dveloppeur de la couche [dao] ne voit plus la couche [Jdbc] ni les tables de la base de donnes dont il veut exploiter le contenu. Il ne voit que l'image objet de la base de donnes, image objet fournie par la couche [Hibernate]. Le pont entre les tables de la base de donnes et les objets manipuls par la couche [dao] est fait principalement de deux faons : par des fichiers de configuration de type XML par des annotations Java dans le code, technique disponible seulement depuis le JDK 1.5 La couche [Hibernate] est une couche d'abstraction qui se veut la plus transparente possible. L'idal vis est que le dveloppeur de la couche [dao] puisse ignorer totalement qu'il travaille avec une base de donnes. C'est envisageable si ce n'est pas lui qui crit la configuration qui fait le pont entre le monde relationnel et le monde objet. La configuration de ce pont est assez dlicate et ncessite une certaine habitude. La couche [4] des objets, image de la BD est appele "contexte de persistance". Une couche [dao] s'appuyant sur Hibernate fait des actions de persistance (CRUD, create - read - update - delete) sur les objets du contexte de persistance, actions traduites par Hibernate en ordres SQL excuts par la couche Jdbc. Pour les actions d'interrogation de la base (le SQL Select), Hibernate fournit au dveloppeur, un langage HQL (Hibernate Query Language) pour interroger le contexte de persistance [4] et non la BD ellemme. Hibernate est populaire mais complexe matriser. La courbe d'apprentissage souvent prsente comme facile est en fait assez raide. Ds qu'on a une base de donnes avec des tables ayant des relations un--plusieurs ou plusieurs--plusieurs, la configuration du pont relationnel / objets n'est pas la porte du premier dbutant venu. Des erreurs de configuration peuvent conduire des applications peu performantes. Devant le succs des produits ORM, Sun le crateur de Java, a dcid de standardiser une couche ORM via une spcification appele JPA (Java Persistence Api) apparue en mme temps que Java 5. La spcification JPA a t implmente par divers produits : Hibernate, Toplink, EclipseLink, OpenJpa, .... Avec JPA, l'architecture prcdente devient la suivante : 4 Objets image de la BD

Couche d'accs aux donnes [dao] 3

Interface [JPA]

Implmentation JPA [Hibernate / ...] 5

Couche [JDBC] 6

Base de Donnes 7

La couche [dao] dialogue maintenant avec la spcification JPA, un ensemble d'interfaces. Le dveloppeur y a gagn en standardisation. Avant, s'il changeait sa couche ORM, il devait galement changer sa couche [dao] qui avait t crite pour dialoguer avec un ORM spcifique. Maintenant, il va crire une couche [dao] qui va dialoguer avec une couche JPA. Quelque soit le produit qui implmente celle-ci, l'interface de la couche JPA prsente la couche [dao] reste la mme. Dans ce document, nous utiliserons une couche [dao] s'appuyant sur une couche JPA/Hibernate ou JPA/EclipseLink. Par ailleurs nous utiliserons le framework Spring 2.8 pour lier ces couches entre-elles. 4

Couche [metier] 2

Couche [dao] 3 7

Objets image de la BD

Interface Implmentation JPA [EclipseLink [JPA] / Hibernate] 5

Couche [JDBC] 6

Spring

Le grand intrt de Spring est qu'il permet de lier les couches par configuration et non dans le code. Ainsi si l'implmentation JPA / Hibernate doit tre remplace par une implmentation Hibernate sans JPA, parce que par exemple l'application s'excute dans un environnement JDK 1.4 qui ne supporte pas JPA, ce changement d'implmentation de la couche [dao] n'a pas d'impact sur le code de la couche [mtier]. Seul le fichier de configuration Spring qui lie les couches entre elles doit tre modifi. Avec Java EE 5, une autre solution existe : implmenter les couches [metier] et [dao] avec des Ejb3 (Enterprise Java Bean version 3) :

http://tahe.developpez.com/java/javaee

5/341

Couche [metier] 2

Couche [dao] 3 7

Objets image de la BD

4

Interface Implmentation JPA [EclipseLink [JPA] / Hibernate] 5

Couche [JDBC] 6

conteneur Ejb3

Nous verrons que cette solution n'est pas trs diffrente de celle utilisant Spring. L'environnement Java EE5 est disponible au sein de serveurs dits serveurs d'applications tels que Sun Application Server 9.x (Glassfish), Jboss Application Server, Oracle Container for Java (OC4J), ... Un serveur d'applications est essentiellement un serveur d'applications web. Il existe galement des environnements EE 5 dits "stand-alone", c.a.d. pouvant tre utiliss en-dehors d'un serveur d'applications. C'est le cas de JBoss EJB3 ou OpenEJB. Dans un environnement EE5, les couches sont implmentes par des objets appels EJB (Enterprise Java Bean). Dans les prcdentes versions d'EE, les EJB (EJB 2.x) taient rputs difficiles mettre en oeuvre, tester et parfois peu-performants. On distingue les EJB2.x "entity" et les EJB2.x "session". Pour faire court, un EJB2.x "entity" est l'image d'une ligne de table de base de donnes et EJB2.x "session" un objet utilis pour implmenter les couches [metier], [dao] d'une architecture multi-couches. L'un des principaux reproches faits aux couches implmentes avec des EJB est qu'elles ne sont utilisables qu'au sein de conteneurs EJB, un service dlivr par l'environnement EE. Cet environnement, plus complexe mettre en oeuvre qu'un environnement SE (Standard Edition), peut dcourager le dveloppeur faire frquemment des tests. Nanmoins, il existe des environnements de dveloppement Java qui facilitent l'utilisation d'un serveur d'application en automatisant le dploiement des Ejb sur le serveur : Eclipse, Netbeans, JDeveloper, IntelliJ IDEA. Nous utiliserons ici Netbeans 6.8 et le serveur d'application Glassfish v3. Le framework Spring est n en raction la complexit des EJB2. Spring fournit dans un environnement SE un nombre important des services habituellement fournis par les environnements EE. Ainsi dans la partie "Persistance de donnes", Spring fournit les pools de connexion et les gestionnaires de transactions dont ont besoin les applications. L'mergence de Spring a favoris la culture des tests unitaires, devenus plus faciles mettre en oeuvre dans le contexte SE que dans le contexte EE. Spring permet l'implmentation des couches d'une application par des objets Java classiques (POJO, Plain Old/Ordinary Java Object), permettant la rutilisation de ceux-ci dans un autre contexte. Enfin, il intgre de nombreux outils tiers de faon assez transparente, notamment des outils de persistance tels que Hibernate, EclipseLink, Ibatis, ... Java EE5 a t conu pour corriger les lacunes de la spcification EJB2. Les EJB 2.x sont devenus les EJB3. Ceux-ci sont des POJOs tagus par des annotations qui en font des objets particuliers lorsqu'ils sont au sein d'un conteneur EJB3. Dans celui-ci, l'EJB3 va pouvoir bnficier des services du conteneur (pool de connexions, gestionnaire de transactions, ...). En-dehors du conteneur EJB3, l'EJB3 devient un objet Java normal. Ses annotations EJB sont ignores. Ci-dessus, nous avons reprsent Spring et un conteneur EJB3 comme infrastructure (framework) possible de notre architecture multi-couches. C'est cette infrastructure qui dlivrera les services dont nous avons besoin : un pool de connexions et un gestionnaire de transactions. avec Spring, les couches seront implmentes avec des POJOs. Ceux-ci auront accs aux services de Spring (pool de connexions, gestionnaire de transaction) par injection de dpendances dans ces POJOs : lors de la construction de ceux-ci, Spring leur injecte des rfrences sur les services dont il vont avoir besoin. avec le conteneur Ejb3, les couches seront implmentes avec des Ejb. Une architecture en couches implmentes avec des Ejb3 est peu diffrente de celles implmentes avec des POJO instancis par Spring. Nous trouverons beaucoup de ressemblances.

pour terminer, nous prsenterons un exemple d'application web multi-couches : 4

Couche [web] 1

Couche [metier] 2

Couche [dao] 3 7

Objets image de la BD

Interface Implmentation JPA [EclipseLink [JPA] / Hibernate] 5

Couche [JDBC] 6

Spring ou Ejb3

http://tahe.developpez.com/java/javaee

6/341

2 PAM - Version 1On se propose dcrire une application console ainsi qu'une application graphique permettant dtablir le bulletin de salaire des assistantes maternelles employes par la "Maison de la petite enfance" d'une commune.

2.1

La base de donnes

Les donnes statiques utiles pour construire la fiche de paie seront places dans une base de donnes que nous dsignerons par la suite dbpam. Cette base de donnes pourrait avoir les tables suivantes : Table EMPLOYES : rassemble des informations sur les diffrentes assistantes maternelles Structure :SS NOM PRENOM ADRESSE VILLE CODEPOSTAL INDICE

numro de scurit sociale de l'employ - cl primaire nom de l'employ son prnom son adresse sa ville son code postal son indice de traitement - cl trangre sur le champ [INDICE] de la table [INDEMNITES]

Son contenu pourrait tre le suivant :

Table COTISATIONS : rassemble des pourcentages ncessaires au calcul des cotisations sociales Structure :CSGRDS CSGD SECU RETRAITE

pourcentage : contribution sociale gnralise + contribution au remboursement de la dette sociale pourcentage : contribution sociale gnralise dductible pourcentage : scurit sociale, veuvage, vieillesse pourcentage : retraite complmentaire + assurance chmage

Son contenu pourrait tre le suivant :

Les taux des cotisations sociales sont indpendants du salari. La table prcdente n'a qu'une ligne. Table INDEMNITES : rassemble les lments permettant le calcul du salaire payer.INDICE BASEHEURE ENTRETIENJOUR REPASJOUR INDEMNITESCP

indice de traitement - cl primaire prix net en euro dune heure de garde indemnit dentretien en euro par jour de garde indemnit de repas en euro par jour de garde indemnit de congs pays. C'est un pourcentage appliquer au salaire de base.

Son contenu pourrait tre le suivant :

http://tahe.developpez.com/java/javaee

7/341

On notera que les indemnits peuvent varier d'une assistante maternelle une autre. Elles sont en effet associes une assistante maternelle prcise via l'indice de traitement de celle-ci. Ainsi Mme Marie Jouveinal qui a un indice de traitement de 2 (table EMPLOYES) a un salaire horaire de 2,1 euro (table INDEMNITES).

2.2

Mode de calcul du salaire d'une assistante maternelle

Nous prsentons maintenant le mode de calcul du salaire mensuel d'une assistante maternelle. Il ne prtend pas tre celui utilis dans la ralit. Nous prenons pour exemple, le salaire de Mme Marie Jouveinal qui a travaill 150 h sur 20 jours pendant le mois payer. Les lments suivants sont pris en compte :[TOTALHEURES]: total des heures travailles dans le mois [TOTALJOURS]: total des jours travaills dans le mois [TOTALHEURES]=150 [TOTALJOURS]= 20

Le salaire de base de l'assistante maternelle est donn par la formule suivante : Un certain nombre de cotisations sociales doivent tre prleves sur ce salaire de base :

[SALAIREBASE]=([TOTALHEURES]*[BAS EHEURE])*(1+[INDEMNITESCP]/100)

[SALAIREBASE]=(150*[2.1])*(1+0.15 )= 362,25

Contribution sociale gnralise et contribution au remboursement de la dette sociale : [SALAIREBASE]*[CSGRDS/100] Contribution sociale gnralise dductible : [SALAIREBASE]*[CSGD/100] Scurit sociale, veuvage, vieillesse : [SALAIREBASE]*[SECU/100] Retraite Complmentaire + AGPF + Assurance Chmage : [SALAIREBASE]*[RETRAITE/100]

CSGRDS : 12,64 CSGD : 22,28 Scurit sociale : 34,02 Retraite : 28,55

Total des cotisations sociales : Par ailleurs, l'assistante maternelle a droit, chaque jour travaill, une indemnit d'entretien ainsi qu' une indemnit de repas. A ce titre elle reoit les indemnits suivantes : Au final, le salaire net payer l'assistante maternelle est le suivant :

[COTISATIONSSOCIALES]=[SALAIREBAS E]*(CSGRDS+CSGD+SECU+RETRAITE)/10 0 [INDEMNITS]=[TOTALJOURS]*(ENTRET IENJOUR+REPASJOUR)

[COTISATIONSSOCIALES]=97,48

[INDEMNITES]=104

[SALAIREBASE][COTISATIONSSOCIALES]+ [INDEMNITS]

[salaire NET]=368,77

2.3

Fonctionnement de l'application console

Voici un exemple de ce qui est attendu. L'ensemble des excutables et des fichiers de configuration ncessaires l'application console sont rassembls dans un rpertoire :

http://tahe.developpez.com/java/javaee

8/341

1

2

[pam-spring-ui-metier-dao-jpa-eclipselink.jar] (1) contient l'application que nous allons crire le dossier [lib] (2) contient les bibliothques de classes ncessaires au projet

Voici un exemple d'excution de l'application console dans une fentre Dos :1. dos>java -jar pam-spring-ui-metier-dao-jpa-eclipselink.jar 254104940426058 150 20 2. 3. Valeurs saisies : 4. N de scurit sociale de l'employ : 254104940426058 5. Nombre d'heures travailles : 150 6. Nombre de jours travaills : 20 7. 8. Informations Employ : 9. Nom : Jouveinal 10. Prnom : Marie 11. Adresse : 5 rue des Oiseaux 12. Ville : St Corentin 13. Code Postal : 49203 14. Indice : 2 15. 16. Informations Cotisations : 17. CSGRDS : 3.49 % 18. CSGD : 6.15 % 19. Retraite : 7.88 % 20. Scurit sociale : 9.39 % 21. 22. Informations Indemnits : 23. Salaire horaire : 2.1 euro 24. Entretien/jour : 2.1 euro 25. Repas/jour : 3.1 euro 26. Congs Pays : 15.0 % 27. 28. Informations Salaire : 29. Salaire de base : 362.25 euro 30. Cotisations sociales : 97.48 euro 31. Indemnits d'entretien : 42.0 euro 32. Indemnits de repas : 62.0 euro 33. Salaire net : 368.77 euro

On crira un programme qui recevra les informations suivantes : 1. 2. 3. n de scurit sociale de l'assistante maternelle ( 254104940426058 dans l'exemple - ligne 1) nombre total d'heures travailles (150 dans l'exemple - ligne 1) nombre total de jours travaills (20 dans l'exemple - ligne 1)

On voit que :

lignes 9-14 : affichent les informations concernant l'employ dont on a donn le n de scurit sociale lignes 17-20 : affichent les taux des diffrentes cotisations lignes 23-26 : affichent les indemnits associes l'indice de traitement de l'employ (ici l'indice 2) lignes 29-33 : affichent les lments constitutifs du salaire payer

L'application signale les erreurs ventuelles : Appel sans paramtres :

http://tahe.developpez.com/java/javaee

9/341

dos>java -jar pam-spring-ui-metier-dao-jpa-eclipselink.jar Syntaxe : pg num_securite_sociale nb_heures_travailles nb_jours_travaills

Appel avec des donnes errones :dos>java -jar pam-spring-ui-metier-dao-jpa-eclipselink.jar Le nombre d'heures travailles [150x] est erron Le nombre de jours travaills [20x] est erron 254104940426058 150x 20x

Appel avec un n de scurit sociale erron :dos>java -jar pam-spring-ui-metier-dao-jpa-eclipselink.jar xx 150 20 L'erreur suivante s'est produite : L'employ de n[xx] est introuvable

2.4

Fonctionnement de l'application graphique

L'application graphique permet le calcul des salaires des assistantes maternelles au travers d'un formulaire Swing :

6 1 2 3 4

5

les informations passes en paramtres au programme console, sont maintenant saisies au moyen des champs de saisie [1, 2, 3]. le bouton [4] demande le calcul du salaire le formulaire affiche les diffrents lments du salaire jusqu'au salaire net payer [5]

La liste droulante [1, 6] ne prsente pas les ns SS des employs mais les noms et prnoms de ceux-ci. On fait ici l'hypothse qu'il n'y a pas deux employs de mmes nom et prnom.

3 Implmentation JPA de la couche de persistance des donnes3.1 Les entits JPA

Nous adopterons l'architecture suivante pour notre application console :

http://tahe.developpez.com/java/javaee

10/341

Couche [ui] 1

Couche [metier] 2

Couche [dao] 3 7

Objets image de la BD

4

Interface [JPA]

Implmentation [EclipseLink/ Hibernate] 5

Couche [JDBC] 6

Spring

La persistance des donnes en base de donnes sera assure par une implmentation JPA / Hibernate ou JPA / EclipseLink. La couche JPA fera le pont entre les tables [COTISATIONS, INDEMNITES, EMPLOYES] et les entits [Cotisation, Indemnite, Employe]. Question : Donnez un code possible pour les entits [Cotisation, Indemnite, Employe]. Lectures conseilles : [ref1], paragraphe 2.4. Notes :

les entits feront partie d'un paquetage nomm [jpa] chaque entit aura un n de version si deux entits sont lies par une relation, seule la relation principale sera construite. La relation inverse ne le sera pas.

La structure de la base de donnes MySQL sera la suivante :1. 2. -- -------------------------------------------------------3. 4. -5. -- Structure de la table 'cotisations' 6. -7. 8. CREATE TABLE cotisations ( 9. ID bigint(20) NOT NULL AUTO_INCREMENT, 10. SECU double NOT NULL, 11. RETRAITE double NOT NULL, 12. CSGD double NOT NULL, 13. CSGRDS double NOT NULL, 14. VERSION int(11) NOT NULL, 15. PRIMARY KEY (ID) 16. ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 17. 18. -- -------------------------------------------------------19. 20. -21. -- Structure de la table 'employes' 22. -23. 24. CREATE TABLE employes ( 25. ID bigint(20) NOT NULL AUTO_INCREMENT, 26. PRENOM varchar(20) NOT NULL, 27. SS varchar(15) NOT NULL, 28. ADRESSE varchar(50) NOT NULL, 29. CP varchar(5) NOT NULL, 30. VILLE varchar(30) NOT NULL, 31. NOM varchar(30) NOT NULL, 32. VERSION int(11) NOT NULL, 33. INDEMNITE_ID bigint(20) NOT NULL, 34. PRIMARY KEY (ID), 35. UNIQUE KEY SS (SS), 36. KEY FK_EMPLOYES_INDEMNITE_ID (INDEMNITE_ID) 37. ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 38. 39. -- -------------------------------------------------------40. 41. -42. -- Structure de la table 'indemnites' 43. -44. 45. CREATE TABLE indemnites ( 46. ID bigint(20) NOT NULL AUTO_INCREMENT, 47. ENTRETIEN_JOUR double NOT NULL, 48. REPAS_JOUR double NOT NULL,

http://tahe.developpez.com/java/javaee

11/341

49. INDICE int(11) NOT NULL, 50. INDEMNITES_CP double NOT NULL, 51. BASE_HEURE double NOT NULL, 52. VERSION int(11) NOT NULL, 53. PRIMARY KEY (ID), 54. UNIQUE KEY INDICE (INDICE) 55. ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 56. 57. -58. -- Contraintes pour les tables exportes 59. -60. 61. -62. -- Contraintes pour la table `employes` 63. -64. ALTER TABLE `employes` 65. ADD CONSTRAINT FK_EMPLOYES_INDEMNITE_ID FOREIGN KEY (INDEMNITE_ID) REFERENCES indemnites (ID);

3.2

Configuration de la couche JPA

Une fois les entits JPA crites, il est possible de faire une premire srie de tests en gnrant la base de donnes image des entits l'aide d'un script ant. Nous ferons ces tests l'intrieur du projet Netbeans [pam-jpa-hibernate-tools] suivant :

4 1 5 3 2 9 6 8 7

en [1] : le projet Java. On y notera : [2] : le paquetage [jpa] et les trois entits [Cotisation, Employe, Indemnite] [3] : le fichier [persistence.xml] qui configure la couche JPA en [4] : le dossier complet du projet : [5, 7] : le dossier [conf-bd] contient les fichiers [persistence.xml] pour divers SGBD [6, 8] : le dossier [conf-ddl] contient le schma de la base de donnes gnre par la couche JPA pour chacun des SGBD prcdents en [9] : le script [ant-hibernate.xml] est le script ant qui va gnrer la base de donnes partir des entits JPA.

Question : donner le contenu du fichier [persistence.xml] qui connecterait la couche JPA la base de donnes ayant les caractristiques suivantes : [SGBD : MySQL5, url : //localhost:3306/dbpam_hibernate, propritaire de la connexion : dbpam, mot de passe : dbpam]. Notes : suivre l'exemple du paragraphe 2.1.5 de [ref1]

4 Mise en oeuvre des tests de la couche JPANous mettons en place l'environnement de tests de la couche JPA dveloppe prcdemment. Pour cela, nous utilisons l'IDE Netbeans 6.8 (http://www.netbeans.org/). L'objectif de ces tests est de gnrer la base de donnes MySQL partir de :

la dfinition des entits JPA la dfinition du fichier [persistence.xml] qui dfinit l'implmentation JPA utilise ainsi que l'url de la base de donnes dont la couche JPA est l'image. Nous utiliserons deux implmentations JPA : Hibernate et EclipseLink.

http://tahe.developpez.com/java/javaee

12/341

4.1

Implmentation JPA / Hibernate

Nous allons utiliser l'architecture suivante pour crer la base de donnes partir des entits JPA :

Script ant de gnration de la base de donnes

Interface [JPA]

Implmentation [Hibernate]

Couche [JDBC]

Les entits JPA et le fichier [persistence.xml] qui configure l'implmentation JPA et l'accs la base de donnes sont ceux dfinis prcdemment. Pour crer l'environnement de test, on pourra procder comme suit :

crer le projet Netbeans :

1 3 2

4 5

8 6 9

7

11

10

http://tahe.developpez.com/java/javaee

13/341

[1] : option [File / New Project] [2,3] : choisir la catgorie [General] et le type de projet [Java Application] [4] : explique le type du projet [5] : on passe l'tape suivante [6,7] : l'aide de [7], on dsigne le dossier [6] dans lequel sera cr le sous-dossier du projet. [8] : on donne un nom au projet [9] : prcise le dossier qui va tre cr pour le projet [10] : par dfaut, l'option [Main Class] est coche. Elle entrane la cration d'une classe dite principale avec la mthode statique void main (String[] args). Une classe principale est ncessaire pour avoir une gnration complte du projet. Nous l'appelons [Main] et la plaons dans un paquetage [main]. Nous terminons l'assistant de cration du projet avec le bouton [Finish] non reprsent. [11] : le projet a t cr. La classe [Main] cre est la suivante :

1. package main; 2. 3. public class Main { 4. 5. /** Creates a new instance of Main */ 6. public Main() { 7. } 8. 9. /** 10. * @param args the command line arguments 11. */ 12. public static void main(String[] args) { 13. // TODO code application logic here 14. } 15. 16. }

associer au projet cr les bibliothques de classes dont il va avoir besoin. Celles-ci ont t rassembles dans divers dossiers :

1

4

2 3

5 6 7

8

en [1] : l'emplacement du dossier [lib] qui contient les classes externes ncessaires au projet. Il est au mme niveau que les dossiers des projets Netbeans qui vont tre crs dans ce document. en [2] : les six sous-dossiers du dossier [lib] en [3] : le dossier [divers] contient les pilotes Jdbc des SGBD tests, l'archive log4j qui gre les logs de l'application en [4] : le dossier [hibernate-tools] contient les classes de l'implmentation JPA / Hibernate

http://tahe.developpez.com/java/javaee

14/341

en [5] : le dossier [eclipselink] contient les classes de l'implmentation JPA / EclipseLink 2.0 en [6] : le dossier [openejb] contient les classes du conteneur Ejb OpenEJB 3.1 en [7] : le dossier [spring] contient les classes du framework Spring 2.8 en [8] : le dossier [client-glassfish-v3] contient les classes ncessaires la communication entre un client distant et un EJB dploy sur un serveur Glassfish v3 Pour associer des bibliothques de classes (.jar) au projet Netbeans, on procde de la faon suivante :

2 5 1 3

4

6

en [1] : clic droit sur [Libraries] puis slectionner l'option [Add JAR/Folder] qui permet d'ajouter des archives Java (.jar) au Classpath du projet. en [2] : naviguer jusqu'au dossier qui contient les .jar ajouter en [3] : slectionner les . jar dsirs. Ils apparaissent en [4] en [5] : on prcise que les bibliothques du projet doivents tre rfrences par leur chemin relatif au chemin du projet plutt que par leur chemin absolu. Cela permet de dplacer le projet et ses bibliothques ailleurs dans le systme de fichiers. en [5] : valider la slection on fait ce processus pour les dossiers [divers, hibernate-tools]. [divers] nous apporte les pilotes Jdbc dont nous aurons besoin pour travailler avec divers SGBD. [hibernate-tools] nous apporte les archives de l'implmentation JPA / Hibernate ainsi que l'archive [hibernate-tools] dont nous aurons besoin dans un script ant. Le rsultat obtenu est le suivant (vue partielle) [1] : 1 2

[2] : insrer dans le projet le code des entits JPA et celui du fichier de configuration [persistence.xml] une fois disponibles les sources Java des entits JPA, le fichier de configuration [persistence.xml], les bibliothques de classes ncessaires la compilation et l'excution du projet, on peut gnrer celui-ci :

http://tahe.developpez.com/java/javaee

15/341

2 1b 1 3a

3b 6

7

4 5

[1] : la gnration du projet [2] : le projet est gnr dans le dossier [dist] de l'onglet [Files]. On y trouve trois lments : le dossier qui contient les bibliothques de classes tierces associes au projet (cf [7]). Ce dossier n'est pas gnr si le projet n'a pas de classe principale. C'est pourquoi nous avons laiss l'assistant crer une classe principale dont nous n'avions pas besoin pour les tests ant que nous voulons faire. l'archive .jar [3a, 3b] rsultat de la compilation de la branche [Source Packages] du projet. Sous forme compresse, on retrouve l'arborescence et le contenu de la branche [Source Packages] [1b] la diffrence que les .java ont t compils (4,5). Le .jar [3a,3b] porte le nom du projet. [6] un fichier [MANIFEST.MF] qui configure l'excution du .jar. Son contenu est le suivant :

1. 2. 3. 4. 5.

Manifest-Version: 1.0 Ant-Version: Apache Ant 1.7.1 Created-By: 10.0-b23 (Sun Microsystems Inc.) Main-Class: main.Main Class-Path: lib/derbyclient.jar lib/hsqldb.jar lib/jaybird-full-2.1.1. jar lib/log4j-1.2.13.jar lib/mysql-connector-java-5.0.5-bin.jar lib/o 6. jdbc14.jar lib/postgresql-8.2-505.jdbc3.jar lib/sqljdbc.jar lib/antlr -2.7.6.jar ... 7. X-COMMENT: Main-Class will be added automatically by build

Le fichier .jar peut tre excut dans une fentre Dos / Windows avec la commande suivante :dos>java -jar "\pam-jpa-hibernate-tools.jar"

o reprsente le chemin du dossier dans la copie d'cran [2]. La machine virtuelle Java (JVM) utilise le fichier [META-INF / MANIFEST.MF] pour savoir comment excuter le .jar : ligne 4 : l'attribut [Main-Class] dsigne la classe qui contient la mthode statique void main(String[] args) que la JVM doit excuter pour lancer l'application. ligne 5 : l'attribut [Class-Path] dsigne la liste des .jar explorer par la JVM lorsque l'application rclame une classe qui n'est pas dans le .jar excut. L'environnement ncessaire la cration de la base de donnes, image des entits JPA, est dsormais prt. Nous allons utiliser un script ant pour faire cette gnration. Cette technique est dcrite au paragraphe [2.1.6] de [ref1].

http://tahe.developpez.com/java/javaee

16/341

10 9

8

Le script [ant-hibernate.xml] (8) va permettre de gnrer la base de donnes image de la couche JPA. Il mettra galement le schma de la base de donnes gnre dans le fichier [ddl/schema.sql]. Pour cela, nous crons le dossier [ddl] [9]. Le script [ant-hibernate.xml] est le suivant :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41.

ligne 1 : le projet [ant] s'appelle "jpa-hibernate". Il rassemble un ensemble de tches dont l'une est la tche par dfaut : ici la tche nomme "DDL". Un script ant est appel pour excuter une tche T. Si celle-ci n'est pas prcise, c'est la tche par dfaut qui est excute. basedir="." indique que pour tous les chemins relatifs trouvs dans le script, le point de dpart du chemin est le dossier dans lequel se trouve le script ant. lignes 3-10 : dfinissent des variables de script avec la balise . La variable peut ensuite tre utilise dans le script avec la notation ${nomVariable}. Les noms peuvent tre quelconques. Attardons-nous sur les variables dfinies aux lignes 9-10 :

http://tahe.developpez.com/java/javaee

17/341

ligne 9 : dfinit une variable nomme "src.java.dir" (le nom est libre) qui va, dans la suite du script, dsigner le dossier qui contient les codes source Java. Sa valeur est "src", un chemin relatif au dossier dsign par l'attribut basedir (ligne 1). Il s'agit donc du chemin "./src" o . dsigne ici le dossier qui contient le script ant. C'est bien dans le dossier src que se trouvent les codes source Java (cf [9] plus haut). ligne 10 : dfinit une variable nomme "dist.dir" qui va, dans la suite du script, dsigner le dossier qui contient les archives jar dont ont besoin les tches Java du script. Sa valeur dsigne le dossier (3) qui, on le sait, contient une arborescence avec les archives .jar et les fichiers .class du projet. lignes 13-17 : la balise sert dfinir des lments du classpath que devront utiliser les tches ant. Ici, le path "project.classpath" (le nom est libre) rassemble les archives .jar du dossier , c.a.d. les jars du dossier /lib et celui du projet [swing-metier-dao-jpa-spring-hibernate.jar] (3a, 3b). ligne 20 : dfinition d'une tche l'aide de la balise . Une telle tche a vocation tre rutilise ailleurs dans le script. C'est une facilit de codage. Parce que la tche est utilise divers endroits du script, on la dfinit une fois avec la balise et on la rutilise ensuite via son nom, lorsqu'on en a besoin. la tche s'appelle hibernatetool (attribut name). sa classe est dfinie par l'attribut classname. Ici, la classe dsigne sera trouve dans l'archive [hibernate-tools.jar] du dosssier /lib. l'attribut classpathref indique ant o chercher la classe prcdente les lignes 25-30 concernent la tche qui nous intresse ici, celle de la gnration du schma de la base de donnes image des objets @Entity de notre projet Netbeans. Une tche ant est dfinie au moyen de la balise . ligne 23 : la tche s'appelle DDL (comme Data Definition Language, le SQL associ la cration des objets d'une base de donnes). lignes 24-29 : la tche [hibernatetool] dfinie ligne 20 est appele. On lui passe de nombreux paramtes, outre ceux dj dfinis ligne 20 : ligne 24 : le dossier de sortie des rsultats produits par la tche sera le dossier courant . ligne 26 : indique la tche [hibernatetool] comment elle peut connatre son environnement d'excution : la balise lui indique qu'elle est dans un environnement JPA et qu'elle doit donc utiliser le fichier [META-INF/persistence.xml] qu'elle trouvera ici dans son classpath, c.a.d dans le dossier . la ligne 28 fixe les conditions de gnration de la base de donnes : drop=true indique que des ordres SQL drop table doivent tre mis avant la cration des tables, create=true indique que le fichier texte des ordres SQL de cration de la base doit tre cr, outputfilename indique le nom de ce fichier SQL - ici schema.sql dans le dossier du projet Eclipse, export=false indique que les ordres SQL gnrs ne doivent pas tre jous dans une connexion au SGBD. Ce point est important : il implique que pour excuter la tche, le SGBD cible n'a pas besoin d'tre lanc. delimiter fixe le caractre qui spare deux ordres SQL dans le schma gnr, format=true demande ce qu'un formatage de base soit fait sur le texte gnr. les lignes 33-39 dfinissent la tche nomme BD. Elle est identique la tche DDL prcdente, si ce n'est que cette fois elle gnre la base de donnes (export="true" de la ligne 38). La tche ouvre une connexion sur le SGBD avec les informations trouves dans [persistence.xml], pour y jouer le schma SQL et gnrer la base de donnes. Pour excuter la tche BD, il faut donc que le SGBD soit lanc.

Nous testons maintenant la couche JPA [entits, persistence.xml] avec le SGBD MySQL5. Le mode opratoire est le suivant : 1. 2. 3. lancer MySQL5 avec les outils d'administration de MySQL5, crer une base de donnes appele [dbpam_hibernate] ainsi qu'un utilisateur [dbpam / dbpam] ayant tous les droits sur la base [dbpam_hibernate] (cf paragraphe 5.5 de [ref1]) compiler le projet Netbeans :

1

2

4.

dans l'onglet [Files] de Netbeans, lancer la tche BD du script [ant-hibernate.xml] :

On obtient les rsultats suivants dans la console de Netbeans :

http://tahe.developpez.com/java/javaee

18/341

1. BD: 2. Executing Hibernate Tool with a JPA Configuration 3. 1. task: hbm2ddl (Generates database schema) 4. alter table employes 5. drop 6. foreign key FK4722E6BC73F24A67; 7. drop table if exists cotisations; 8. drop table if exists employes; 9. drop table if exists indemnites; 10. create table cotisations ( 11. ID bigint not null auto_increment, 12. SECU double precision not null, 13. RETRAITE double precision not null, 14. CSGD double precision not null, 15. CSGRDS double precision not null, 16. VERSION integer not null, 17. primary key (ID) 18. ) ENGINE=InnoDB; 19. create table employes ( 20. ID bigint not null auto_increment, 21. PRENOM varchar(20) not null, 22. SS varchar(15) not null, 23. ADRESSE varchar(50) not null, 24. CP varchar(5) not null, 25. VILLE varchar(30) not null, 26. NOM varchar(30) not null, 27. VERSION integer not null, 28. INDEMNITE_ID bigint not null, 29. primary key (ID), 30. unique (SS) 31. ) ENGINE=InnoDB; 32. create table indemnites ( 33. ID bigint not null auto_increment, 34. ENTRETIEN_JOUR double precision not null, 35. REPAS_JOUR double precision not null, 36. INDICE integer not null, 37. INDEMNITES_CP double precision not null, 38. BASE_HEURE double precision not null, 39. VERSION integer not null, 40. primary key (ID), 41. unique (INDICE) 42. ) ENGINE=InnoDB; 43. alter table employes 44. add index FK4722E6BC73F24A67 (INDEMNITE_ID), 45. add constraint FK4722E6BC73F24A67 46. foreign key (INDEMNITE_ID) 47. references indemnites (ID); 48. BUILD SUCCESSFUL (total time: 3 seconds)

Les logs de la console montrent le schma de la base gnre. Ce schma peut galement tre retrouv dans le fichier [ddl/schema.sql] :

lignes 10-18 : la table [COTISATIONS] lignes 19-31 : la table [EMPLOYES] lignes 32-42 : la table [INDEMNITES] lignes 43-47 : la cl trangre (INDEMNITE_ID) de la table [EMPLOYES] sur la colonne ID de la table [INDEMNITES].

Pour vrifier que la base MySQL5 [dbpam_hibernate] a t gnre, nous procdons de la faon suivante :

http://tahe.developpez.com/java/javaee

19/341

1

2

3

dans l'onglet [1] [Services], la branche [Databases] liste les connexions des SGBD configures par l'utilisateur. Pour crer une connexion un SGBD, il faut donner deux informations Netbeans : o trouver le pilote Jdbc du SGBD les coordonnes de l'url de la base de donnes laquelle on veut se connecter. Ces informations se donnent en deux temps : d'abord le pilote Jdbc s'il n'est pas dj dans la liste des drivers disponibles [Databases / Drivers] [2], puis l'url de la base de donnes [3].

Netbeans 6.8 est livr avec le pilote Jdbc de MySQL dj configur dans la branche [Databases / Drivers]. Pour l'exemple, ajoutons cette branche le pilote Jdbc du SGBD Firebird. Celui-ci se trouve dans le dossier [lib / divers]. 1 4 2 3

5 6

slectionner la feuille [Databases / Drivers] de l'arborescence [2], cliquer droit et prendre l'option [New Driver] l'aide de [3], dsigner l'emplacement du pilote Jdbc de MySQL5. Dans ce TD, on le trouvera dans le dossier [lib / divers] (cf page 14). L'archive du pilote Jdbc apparat en [4] le nom de la classe du pilote Jdbc apparat normalement en [5]. Si rien n'apparat ou si vous connaissez la classe et que celle affiche n'est pas la bonne, utiliser le bouton [6] pour trouver la classe. ceci fait, cliquer [OK]. Le pilote Jdbc de Firebird est ajout la liste des pilotes Jdbc disponibles :

Maintenant, crons une connexion vers la base MySQL [dbpam_hibernate] dans laquelle le script [ant-hibernate.xml] a du crer des tables issues de la configuration JPA du projet :

http://tahe.developpez.com/java/javaee

20/341

2 1 3 4 5 6

7

en [1] : cliquer droit sur le pilote JDBC MySQL et choisir [Connect Using...] pour crer la connexion la base MySQL5 / dbpam_hibernate. en [2] : le nom de la machine sur laquelle se trouve le SGBD MySQL en [3] : le port d'coute du SGBD en [4] : le nom de la base de donnes laquelle on veut se connecter en [5] : le propritaire de la connexion en [6] : son mot de passe [dbpam] en [7] : l'url Jdbc de la base de donnes faire [OK]

La connexion est alors ajoute la liste des connexions configures : 1 3 2 1 5

4

en [1] : les 3 tables gnres par le script [ant-hibernate.xml] en [2] : la structure de la table [COTISATIONS] en [3] : la structure de table [EMPLOYES] avec en [4] sa cl trangre sur la colonne INDEMNITES(ID) en [5] : la structure de table [INDEMNITES]

Pour voir le contenu d'une table :

http://tahe.developpez.com/java/javaee

21/341

2 3

4 1

en [1] : on demande voir le contenu de la table [employes] en [3] : la requte SQL mise en [2] : la connexion sur laquelle elle est mise en [4] : le rsultat de la requte la table est vide.

Travail pratique : Refaire le travail prcdent avec certains des SGBD suivants : Oracle XE, SQL Server Express, Firebird, Apache Derby, HSQL. A chaque fois, sauvegarder le fichier [schema.sql] gnr par le script [ant-hibernate.xml] dans le dossier [ddl / sgbd] o sgbd dsigne le SGBD utilis pour le test. Aprs avoir chang le SGBD dans le fichier [persistence.xml], rgnrer le projet (option Build Project) avant d'excuter le script ant.

4.2

Implmentation JPA / EclipseLink

L'architecture de notre application devient la suivante :

Programme principal [Main]

Interface [JPA]

Implmentation [EclipseLink]

Couche [JDBC]

Nous crons un nouveau projet [pam-jpa-eclipselink] [1, 2, 3, 4] : 1

2 3

http://tahe.developpez.com/java/javaee

22/341

5 4

6

En [5], nous ajoutons au projet les entits JPA du projet prcdent. Des erreurs apparaissent parce que notre projet n'a pas dfini de bibliothques pour l'implmentation JPA. en [6], nous ajoutons les bibliothques ncessaires au projet : celles de l'implmentation JPA EclipseLink qu'on trouve dans le dossier [lib/eclipselink] celle du pilote Jdbc du SGBD MySQL qu'on trouve dans le dossier [lib/divers]

Le projet volue alors de la faon suivante [7] :

7

Il ne prsente plus d'erreurs. Rappelons qu'une couche JPA est dfinie par deux lments : des entits JPA - nous venons de les dfinir un fichier [META-INF/persistence.xml] qui dfinit l'implmentation JPA utilise et les proprits de celle-ci. Parmi ces dernires, il y a les paramtres de connexion la base de donnes. Netbeans peut nous aider dfinir le fichier [persistence.xml] en procdant de la faon suivante :

crer une base de donnes MySQL [dbpam_eclipselink] de propritaire [dbpam] avec le mot de passe [dbpam]. On procdera comme il a t fait pour la base [dbpam_hibernate].

Netbeans permet de gnrer le fichier [persistence.xml] pour une base existante et une implmentation JPA donne. Tout d'abord, nous crons dans l'onglet [Services] de Netbeans, une connexion la base MySQL [dbpam_eclipselink]. On procdera comme il a t vu page 20 pour la connexion la base [dbpam_hibernate]. On obtient le rsultat suivant :

http://tahe.developpez.com/java/javaee

23/341

1

2

Pour l'instant, la base [dbpam_eclipselink] est sans tables. Une fois la connexion la base dfinie, il est possible de gnrer le fichier [persistence.xml] :

en [2], clic droit sur le projet / New / Other

5 6 7 4 3 8

choisir la catgorie [Persistence] [3] et le type [Persistence Unit] [4] - faire [Next] en [5] le nom de l'unit de persistence. Ici, il est gnr automatiquement par Netbeans. On peut le changer. en [6] choisir l'implmentation JPA dsire. Ici, on choisit EclipseLink en [7] dsigner la connexion Netbeans relie la base de donnes cible de la couche JPA. Ici, nous dsignons la connexion la base [dbpam_eclipselink] que nous venons de crer. en [8] indiquer la stratgie de gnration des tables de la base de donnes lorsque la couche JPA est construite : None : rien n'est fait Drop and Create : la couche JPA supprime les tables existantes (Drop) et les recre (Create) Create : la couche JPA cre les tables (Create). Si elles existent dj, les ordres SQL CREATE chouent mais ne provoquent pas de plantage. Ici, nous choisissons le mode [Create].

Lorsqu'on termine l'assistant de cration du fichier [persistence.xml], le projet volue de la faon suivante :

http://tahe.developpez.com/java/javaee

24/341

1

3 2

en [1], le fichier [persistence.xml] gnr en [2], les bibliothques d'EclipseLink ont t rajoutes. Elles sont dsormais prsentes deux fois. On peut supprimer l'une des deux versions. Nous gardons celle rfrenant les bibliothques du dossier [lib/eclipselink] [3].

Double-cliquons sur le fichier [persistence.xml]. Celui-ci peut tre vu selon deux modes : 1 2

[1] : mode texte [XML] [2] : mode [Design]

Prenons le mode [XML]. Le fichier [persistence.xml] est le suivant :1. 2. 3. 4. org.eclipse.persistence.jpa.PersistenceProvider 5. 6. 7. 8. 9. 10. 11. 12. 13.

ligne 3 : le nom de l'unit de persistance et son mode de transaction. Ici RESOURCE_LOCAL indique que c'est le code de l'utilisateur qui a la charge de les grer. ligne 4 : l'implmentation JPA utilise, ici EclipseLink lignes 5-11 : les proprits (paramtres) de l'implmentation JPA ligne 6 : l'url Jdbc de la base de donnes cible ligne 7 : le propritaire des connexions qui seront faites sur la base ligne 9 : son mot de passe ligne 8 : le pilote Jdbc du SGBD cible MySQL ligne 10 : la stratgie de cration des tables de la base lorsque la couche JPA est instancie

On rajoutera manuellement la proprit suivante :

http://tahe.developpez.com/java/javaee

25/341

qui fixe le type de la base de donnes cible. En mode [Design], on a la vue suivante :

1 2

Pa dfaut, la couche JPA grera toutes les classes ayant l'annotation @Entity [1]. On peut aussi dclarer explicitement ces classes avec le bouton [2] :

3

4

en [3], on dsigne les entits JPA qui apparaissent alors en [4]

Le fichier [persistence.xml] volue de la faon suivante dans la vue texte :1. 2. 3. 4. org.eclipse.persistence.jpa.PersistenceProvider 5. jpa.Cotisation 6. jpa.Employe 7. jpa.Indemnite 8. 9. ... 10. 11. 12.

Les entits JPA gres par la couche JPA ont t dfinies aux lignes 5-7 par une balise .

http://tahe.developpez.com/java/javaee

26/341

La couche JPA tant dfinie, nous allons l'instancier partir de la classe principale du projet [main.Main] :

La classe [Main.java] sera la suivante :1. package main; 2. 3. import javax.persistence.EntityManager; 4. import javax.persistence.EntityManagerFactory; 5. import javax.persistence.Persistence; 6. 7. public class Main { 8. 9. public static void main(String[] args){ 10. // crer l'Entity Manager suffit construire la couche JPA 11. EntityManagerFactory emf=Persistence.createEntityManagerFactory("pam-jpa-eclipselinkPU"); 12. EntityManager em=emf.createEntityManager(); 13. // libration des ressources 14. em.close(); 15. emf.close(); 16. // fin 17. System.out.println("termin"); 18. } 19. }

ligne 11 : on cre un EntityManagerFactory partir de l'unit de persistance [pam-jpa-eclipselinkPU] qui vient d'tre cr. Ce nom est celui de l'attribut name de la balise . ligne 12 : on cre l'objet EntityManager qui est le gestionnaire des entits JPA. La cration de cet objet instancie la couche JPA. Le fichier [persistence.xml] est exploit. Parce que nous avons crit :

la couche JPA va crer les tables images des entits JPA. Ainsi aprs excution devrions-nous voir des tables dans la base de donnes. Essayons.

2 1

3

en [1], la classe [Main] est excute en [2], dans l'onglet [Services], nous rafrachissons la base de donnes [dbpam_eclipselink] en [3], ce rafrachissement fait apparatre 4 tables : une pour chacune des entits JPA et une quatrime appele [sequence] utilise pour gnrer automatiquement les cls primaires des trois autres tables. On dcouvre ainsi, que selon l'implmentation Hibernate ou EclipseLink, la base de donnes gnre n'a pas t la mme.

http://tahe.developpez.com/java/javaee

27/341

Travail pratique : Refaire le travail prcdent avec d'autres SGBD : Oracle XE, SQL Server Express, Firebird, Apache Derby, HSQL, ... Revenons l'architecture dsire pour le projet final : 4

Couche [ui] 1

Couche [metier] 2

Couche [dao] 3 7

Objets image de la BD

Interface [JPA]

Implmentation [EclipseLink] 5

Couche [JDBC] 6

Spring

Les entits JPA [4] sont dsormais crites. Nous abordons maintenant l'criture de la couche [dao] [3] mais auparavant nous allons dfinir les interfaces prsentes par les couches [mtier] et [dao].

5 Les interfaces des couches [metier] et [dao]Dans l'architecture ci-dessus, quelle interface doit offrir la couche [dao] la couche [metier] et quelle interface doit offrir la couche [metier] la couche [ui] ? Une premire approche pour dfinir les interfaces des diffrentes couches est d'examiner les diffrents cas d'usage (use cases) de l'application. Ici nous en avons deux, selon l'interface utilisateur choisie : console ou formulaire graphique. Examinons le mode d'utilisation de l'application console :1. dos>java -jar pam-spring-ui-metier-dao-jpa-eclipselink.jar 254104940426058 150 20 2. 3. Valeurs saisies : 4. N de scurit sociale de l'employ : 254104940426058 5. Nombre d'heures travailles : 150 6. Nombre de jours travaills : 20 7. 8. Informations Employ : 9. Nom : Jouveinal 10. ... 11. 12. Informations Cotisations : 13. CSGRDS : 3.49 % 14. ... 15. 16. Informations Indemnits : 17. ... 18. 19. Informations Salaire : 20. Salaire de base : 362.25 euro 21. Cotisations sociales : 97.48 euro 22. Indemnits d'entretien : 42.0 euro 23. Indemnits de repas : 62.0 euro 24. Salaire net : 368.77 euro

L'application reoit trois informations de l'utilisateur (cf ligne 1 ci-dessus) le n de scurit sociale de l'assistante maternelle le nombre d'heures travailles dans le mois le nombre de jours travaills dans le mois A partir de ces information et d'autres enregistres dans des fichiers de configuration, l'application affiche les informations suivantes :

lignes 4-6 : les valeurs saisies lignes 8-10 : les informations lies l'employ dont on a donn le n de scurit sociale lignes 12-14 : les taux des diffrentes cotisations sociales lignes 16-17 : les diffrentes indemnits verses l'assistante maternelle lignes 19-24 : les lments de la feuille de salaire de l'assistante maternelle

Un certain nombre d'informations doivent tre fournies par la couche [metier] la couche [ui] :

http://tahe.developpez.com/java/javaee

28/341

1. 2. 3. 4.

les informations lies une assistante maternelle identifie par son n de scurit sociale. On trouve ces informations dans la table [EMPLOYES]. Cela permet d'afficher les lignes 6-8. les montants des divers taux de cotisations sociales prlever sur le salaire brut. On trouve ces informations dans la table [COTISATIONS]. Cela permet d'afficher les lignes 10-12. les montants des diverses indemnits lies la fonction d'assistante maternelle. On trouve ces informations dans la table [INDEMNITES]. Cela permet d'afficher les lignes 14-15. les lments constitutifs du salaire affichs lignes 18-22.

De ceci, on pourrait dcider d'une premire criture de l'interface [IMetier] prsente par la couche [metier] la couche [ui] :1. 2. 3. 4. 5. 6. package metier; public interface IMetier { // obtenir la feuille de salaire public FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravailles, int nbJoursTravaills ); }

ligne 1 : les lments de la couche [metier] sont mis dans le paquetage [metier] ligne 5 : la mthode [ calculerFeuilleSalaire ] prend pour paramtres les trois informations acquises par la couche [ui] et rend un objet de type [FeuilleSalaire] contenant les informations que la couche [ui] affichera sur la console. La classe [FeuilleSalaire] pourrait tre la suivante :

1. package metier; 2. 3. import jpa.Cotisation; 4. import jpa.Employe; 5. import jpa.Indemnite; 6. 7. public class FeuilleSalaire { 8. // champs privs 9. private Employe employe; 10. private Cotisation cotisation; 11. private Indemnite indemnite; 12. private ElementsSalaire elementsSalaire; 13. 14. ... 15. }

ligne 9 : l'employ concern par la feuille de salaire - information n 1 affiche par la couche [ui] ligne 10 : les diffrents taux de cotisation - information n 2 affiche par la couche [ui] ligne 11 : les diffrentes indemnits lies l'indice de l'employ - information n 3 affiche par la couche [ui] ligne 12 : les lments constitutifs de son salaire - information n 4 affiche par la couche [ui]

Un second cas d'usage de la couche [mtier] apparat avec l'interface graphique :

2 1

On voit ci-dessus, que la liste droulante [1, 2] prsente tous les employs. Cette liste doit tre demande la couche [mtier]. L'interface de celle-ci volue alors de la faon suivante :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. package metier; import java.util.List; import jpa.Employe; public interface IMetier { // obtenir la feuille de salaire public FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravailles, int nbJoursTravaills ); // liste des employs public List findAllEmployes(); }

http://tahe.developpez.com/java/javaee

29/341

ligne [10] : la mthode qui va permettre la couche [ui] de demander la liste de tous les employs la couche [mtier].

La couche [metier] ne peut initialiser les champs [Employe, Cotisation, Indemnite] de l'objet [FeuilleSalaire] ci-dessus qu'en questionnant la couche [dao] car ces informations sont dans les tables de la base de donnes. Il en est de mme pour obtenir la liste de tous les employs. On peut crer une interface [dao] unique grant l'accs aux trois entits [Employe, Cotisation, Indemnite]. Nous dcidons plutt ici de crer une interface [dao] par entit. L'interface [dao] pour les accs aux entits [Cotisation] de la table [COTISATIONS] sera la suivante :1. package dao; 2. 3. import java.util.List; 4. import jpa.Cotisation; 5. 6. public interface ICotisationDao { 7. // crer une nouvelle cotisation 8. public Cotisation create(Cotisation cotisation); 9. // modifier une cotisation existante 10. public Cotisation edit(Cotisation cotisation); 11. // supprimer une cotisation existante 12. public void destroy(Cotisation cotisation); 13. // chercher une cotisation particulire 14. public Cotisation find(Long id); 15. // obtenir tous les objets Cotisation 16. public List findAll(); 17. 18. }

ligne 6, l'interface [ICotisationDao] gre les accs l'entit [Cotisation] et donc la table [COTISATIONS] de la base de donnes. Notre application n'a besoin que de la mthode [findAll] de la ligne 16 qui permet de retrouver tout le contenu de la table [COTISATIONS]. On a voulu ici se mettre dans un cas plus gnral o toutes les oprations CRUD (Create, Read, Update, Delete) sont effectues sur l'entit. ligne 8 : la mthode [create] cre une nouvelle entit [Cotisation] ligne 10 : la mthode [edit] modifie une entit [Cotisation] existante ligne 12 : la mthode [destroy] supprime une entit [Cotisation] existante ligne 14 : la mthode [find] permet de retrouver une entit [Cotisation] existante via son identifiant id ligne 16 : la mthode [findAll] rend dans une liste toutes les entits [Cotisation] existantes

Attardons-nous sur la signature de la mthode [create] :1. // crer une nouvelle cotisation 2.Cotisation create(Cotisation cotisation);

La mthode create a un paramtre cotisation de type Cotisation. Le paramtre cotisation doit tre persist, c.a.d. ici mis dans la table [COTISATIONS]. Avant cette persistance, le paramtre cotisation a un identifiant id sans valeur. Aprs la persistance, le champ id a une valeur qui est la cl primaire de l'enregistrement ajout la table [COTISATIONS]. Le paramtre cotisation est donc un paramtre d'entre / sortie de la mthode create. Il ne semble pas ncessaire que mthode create rende de plus le paramtre cotisation comme rsultat. La mthode appelante dtenant une rfrence sur l'objet [Cotisation cotisation], si celui-ci est modifi, elle a accs l'objet modifi puisqu'elle a une rfrence dessus. Elle peut donc connatre la valeur que la mthode create a donn au champ id de l'objet [Cotisation cotisation]. La signature de la mthode pourrait donc tre plus simplement :1. // crer une nouvelle cotisation 2. void create(Cotisation cotisation);

Lorsqu'on crit une interface, il est bon de se rappeler qu'elle peut tre utilise dans deux contextes diffrents : local et distant. Dans le contexte local, la mthode appelante et la mthode appele sont excutes dans la mme Jvm :

utilisateur

Couche interface utilisateur [ui]

Couche mtier [metier] JVM

Couche d'accs aux donnes [dao]

Donnes

Si la couche [metier] fait appel la mthode create de la couche [dao], elle a bien une rfrence sur le paramtre [Cotisation cotisation] qu'elle passe la mthode.

http://tahe.developpez.com/java/javaee

30/341

Dans le contexte distant, la mthode appelante et la mthode appele sont excutes dans des Jvm diffrentes : 1 utilisateur Couche interface utilisateur [ui] JVM 1 Couche mtier [metier] 2 3 Rseau tcp /ip Couche d'accs aux donnes [dao] JVM 2 Donnes

Ci-dessus, la couche [metier] s'excute dans la JVM 1 et la couche [dao] dans la JVM 2 sur deux machines diffrentes. Les deux couches ne communiquent pas directement. Entre-elles s'intercale une couche qu'on appellera couche de communication [1]. Celleci est compose d'une couche d'mission [2] et d'une couche de rception [3]. Le dveloppeur n'a en gnral pas crire ces couches de communication. Elles sont gnres automatiquement par des outils logiciels. La couche [metier] est crite comme si elle s'excutait dans la mme Jvm que la couche [dao]. Il n'y a donc aucune modification de code. Le mcanisme de communication entre la couche [metier] et la couche [dao] est le suivant :

la couche [metier] fait appel la mthode create de la couche [dao] en lui passant le paramtre [Cotisation cotisation1] ce paramtre est en fait pass la couche d'mission [2]. Celle-ci va transmettre sur le rseau, la valeur du paramtre cotisation1 et non sa rfrence. La forme exacte de cette valeur dpend du protocole de communication utilis. la couche de rception [3] va rcuprer cette valeur et reconstruire partir d'elle un objet [Cotisation cotisation2] image du paramtre initial envoy par la couche [metier]. On a maintenant deux objets identiques (au sens de contenu) dans deux Jvm diffrentes : cotisation1 et cotisation2. la couche de rception va passer l'objet cotisation2 la mthode create de la couche [dao] qui va le persister en base de donnes. Aprs cette opration, le champ id de l'objet cotisation2 a t initialis par la cl primaire de l'enregistrement ajout la table [COTISATIONS]. Ce n'est pas le cas de l'objet cotisation1 sur lequel la couche [metier] a une rfrence. Si on veut que la couche [metier] ait une rfrence sur l'objet cotisation2, il faut le lui envoyer. Aussi est-on amens changer la signature de la mthode create de la couche [dao] :

1. // crer une nouvelle cotisation 2. Cotisation create(Cotisation cotisation);

avec cette nouvelle signature, la mthode create va rendre comme rsultat l'objet persist cotisation2. Ce rsultat est rendu la couche de rception [3] qui avait appel la couche [dao]. Celle-ci va rendre la valeur (et non la rfrence) de cotisation2 la couche d'mission [2]. la couche d'mission [2] va rcuprer cette valeur et reconstruire partir d'elle un objet [Cotisation cotisation3] image du rsultat rendu par la mthode create de la couche [dao]. l'objet [Cotisation cotisation3] est rendu la mthode de la couche [metier] dont l'appel la mthode create de la couche [dao] avait initi tout ce mcanisme. La couche [metier] peut donc connatre la valeur de cl primaire donn l'objet [Cotisation cotisation1] dont elle avait demand la persistance : c'est la valeur du champ id de cotisation3.

L'architecture prcdente n'est pas la plus courante. On trouve plus frquemment les couches [metier] et [dao] dans la mme Jvm : 1 utilisateur 2 Couche interface utilisateur [ui] JVM 1 3 Rseau tcp /ip Couche mtier [metier] Couche d'accs aux donnes [dao] JVM 2 Donnes

Dans cette architecture, ce sont les mthodes de la couche [metier] qui doivent rendre des rsultats et non celles de la couche [dao]. Nanmoins la signature suivante de la mthode create de la couche [dao] :1. // crer une nouvelle cotisation 2. Cotisation create(Cotisation cotisation);

http://tahe.developpez.com/java/javaee

31/341

nous permet de ne pas faire d'hypothses sur l'architecture rellement mise en place. Utiliser des signatures qui fonctionneront quelque soit l'architecture retenue, locale ou distante, implique que dans le cas o une mthode appele modifie certains de ses paramtres : ceux-ci doivent faire galement partie du rsultat de la mthode appele la mthode appelante doit utiliser le rsultat de la mthode appele et non les rfrences des paramtres modifis qu'elle a transmis la mthode appele. On se laisse ainsi la possibilit de passer une couche d'une architecture locale une architecture distante sans modification de code. Rexaminons, cette lumire, l'interface [ICotisationDao] :1. package dao; 2. 3. import java.util.List; 4. import jpa.Cotisation; 5. 6. public interface ICotisationDao { 7. // crer une nouvelle cotisation 8. public Cotisation create(Cotisation cotisation); 9. // modifier une cotisation existante 10. public Cotisation edit(Cotisation cotisation); 11. // supprimer une cotisation existante 12. public void destroy(Cotisation cotisation); 13. // chercher une cotisation particulire 14. public Cotisation find(Long id); 15. // obtenir tous les objets Cotisation 16. public List findAll(); 17. 18. }

ligne 8 : le cas de la mthode create a t trait ligne 10 : la mthode edit utilise son paramtre [Cotisation cotisation1] pour mettre jour l'enregistrement de la table [COTISATIONS] ayant la mme cl primaire que l'objet cotisation. Elle rend comme rsultat l'objet cotisation2 image de l'enregistrement modifi. Le paramtre cotisation1 n'est lui pas modifi. La mthode doit rendre cotisation2 comme rsultat qu'on soit dans le cadre d'une architecture distante ou locale. ligne 12 : la mthode destroy supprime l'enregistrement de la table [COTISATIONS] ayant la mme cl primaire que l'objet cotisation pass en paramtre. Celui-ci n'est pas modifi. Il n'a donc pas tre rendu. ligne 14 : le paramtre id de la mthode find n'est pas modifi par la mthode. Il n'a pas faire partie du rsultat. ligne 16 : la mthode findAll n'a pas de paramtres. On n'a donc pas l'tudier.

Au final, seule la signature de la mthode create doit tre adapte pour tre utilisable dans le cadre d'une architecture distante. Les raisonnements prcdents seront valables pour les autres interfaces [dao]. Nous ne les rpterons pas et utiliserons directement des signatures utilisables aussi bien dans le cadre d'une architecture distante que locale. L'interface [dao] pour les accs aux entits [Indemnite] de la table [INDEMNITES] sera la suivante :1. package dao; 2. 3. import java.util.List; 4. import jpa.Indemnite; 5. 6. public interface IIndemniteDao { 7. // crer une entit Indemnite 8. public Indemnite create(Indemnite indemnite); 9. // modifier une entit Indemnite 10. public Indemnite edit(Indemnite indemnite); 11. // supprimer une entit Indemnite 12. public void destroy(Indemnite indemnite); 13. // rechercher une entit Indemnite via son identifiant 14. public Indemnite find(Long id); 15. // obtenir toutes les entits Indemnite 16. public List findAll(); 17. 18. }

ligne 6, l'interface [IIndemniteDao] gre les accs l'entit [Indemnite] et donc la table [INDEMNITES] de la base de donnes. Notre application n'a besoin que de la mthode [findAll] de la ligne 16 qui permet de retrouver tout le contenu de la table [INDEMNITES]. On a voulu ici se mettre dans un cas plus gnral o toutes les oprations CRUD (Create, Read, Update, Delete) sont effectues sur l'entit. ligne 8 : la mthode [create] cre une nouvelle entit [Indemnite] ligne 10 : la mthode [edit] modifie une entit [Indemnite] existante ligne 12 : la mthode [destroy] supprime une entit [Indemnite] existante ligne 14 : la mthode [find] permet de retrouver une entit [Indemnite] existante via son identifiant id

http://tahe.developpez.com/java/javaee

32/341

ligne 16 : la mthode [findAll] rend dans une liste toutes les entits [Indemnite] existantes

L'interface [dao] pour les accs aux entits [Employe] de la table [EMPLOYES] sera la suivante :1. package dao; 2. 3. import java.util.List; 4. import jpa.Employe; 5. 6. public interface IEmployeDao { 7. // crer une nouvelle entit Employe 8. public Employe create(Employe employe); 9. // modifier une entit Employe existante 10. public Employe edit(Employe employe); 11. // supprimer une entit Employe 12. public void destroy(Employe employe); 13. // chercher une entit Employe via son identifiant id 14. public Employe find(Long id); 15. // chercher une entit Employe via son n SS 16. public Employe find(String SS); 17. // obtenir toutes les entits Employe 18. public List findAll(); 19. }

ligne 6, l'interface [IEmployeDao] gre les accs l'entit [Employe] et donc la table [EMPLOYES] de la base de donnes. Notre application n'a besoin que de la mthode [findAll] de la ligne 16 qui permet de retrouver tout le contenu de la table [EMPLOYES]. On a voulu ici se mettre dans un cas plus gnral o toutes les oprations CRUD (Create, Read, Update, Delete) sont effectues sur l'entit. ligne 8 : la mthode [create] cre une nouvelle entit [Employe] ligne 10 : la mthode [edit] modifie une entit [Employe] existante ligne 12 : la mthode [destroy] supprime une entit [Employe] existante ligne 14 : la mthode [find] permet de retrouver une entit [Employe] existante via son identifiant id ligne 16 : la mthode [find(String SS)] permet de retrouver une entit [Employe] existante via son n SS. Nous avons vu que cette mthode tait ncessaire l'application console. ligne 18 : la mthode [findAll] rend dans une liste toutes les entits [Employe] existantes. Nous avons vu que cette mthode tait ncessaire l'application graphique.

6 La classe [PamException]La couche [dao] va travailler avec l'API JDBC de Java. Cette API lance des exceptions contrles de type [SQLException] qui prsentent deux inconvnients : elles alourdissent le code qui doit obligatoirement grer ces exceptions avec des try / catch. elles doivent tre dclares dans la signature des mthodes de l'interface [IDao] par un "throws SQLException". Ceci a pour consquence d'empcher l'implmentation de cette interface par des classes qui lanceraient une exception contrle d'un type diffrent de [SQLException]. Pour remdier ce problme, la couche [dao] ne "remontera" que des exceptions non contrles de type [PamException].

PamExceptionCouche [ui] Couche [metier]

[Jpa]Exception

SQLExceptionCouche [JDBC]

Couche [dao]

Implmentation [Jpa / EclipseLink]

Spring

la couche [Jdbc] lance des exceptions de type [SQLException] la couche [Jpa] lance des exceptions propres l'implmentation Jpa utilise la couche [dao] lance des exceptions de type [PamException] non contrles

Ceci a deux consquences :

http://tahe.developpez.com/java/javaee

33/341

la couche [metier] n'aura pas l'obligation de grer les exceptions de la couche [dao] avec des try / catch. Elle pourra simplement les laisser remonter jusqu' la couche [ui]. les mthodes de l'interface [IDao] n'ont pas mettre dans leur signature la nature de l'exception [PamException], ce qui laisse la possiblit d'implmenter cette interface avec des classes qui lanceraient un autre type d'exception non contrle.

La classe [PamException] sera place dans le paquetage [exception] du projet Netbeans :

Son code est le suivant :1. package exception; 2. 3. @SuppressWarnings("serial") 4. public class PamException extends RuntimeException { 5. 6. // code d'erreur 7. private int code; 8. 9. public PamException(int code) { 10. super(); 11. this.code = code; 12. } 13. 14. public PamException(String message, int code) { 15. super(message); 16. this.code = code; 17. } 18. 19. public PamException(Throwable cause, int code) { 20. super(cause); 21. this.code = code; 22. } 23. 24. public PamException(String message, Throwable cause, int code) { 25. super(message, cause); 26. this.code = code; 27. } 28. 29. // getter et setter 30. 31. public int getCode() { 32. return code; 33. } 34. 35. public void setCode(int code) { 36. this.code = code; 37. } 38. 39. }

ligne 4 : [PamException] drive de [RuntimeException]. C'est donc un type d'exceptions que le compilateur ne nous oblige pas grer par un try / catch ou mettre dans la signature des mthodes. C'est pour cette raison, que [PamException] n'est pas dans la signature des mthodes de l'interface [IDao]. Cela permet cette interface d'tre implmente par une classe lanant un autre type d'exceptions, pourvu que celui-ci drive galement de [RuntimeException]. pour diffrencier les erreurs qui peuvent se produire, on utilise le code erreur de la ligne 7. Les trois constructeurs des lignes 14, 19 et 24 sont ceux de la classe parente [RuntimeException] auxquels on a rajout un paramtre : celui du code d'erreur qu'on veut donner l'exception.

Le fonctionnement de l'application, du point de vue des exceptions, sera le suivant :

la couche [dao] encapsulera toute exception rencontre, dans une exception de type [PamException], et relancera cette dernire pour la couche [mtier].

http://tahe.developpez.com/java/javaee

34/341

la couche [mtier] laissera remonter les exceptions lances par la couche [dao]. Elle encapsulera toute exception survenant dans la couche [mtier], dans une exception de type [PamException] et relancera cette dernire pour la couche [ui]. la couche [ui] intercepte toutes les exceptions qui remontent des couches [mtier] et [dao]. Elle se contentera d'afficher l'exception sur la console ou l'interface graphique.

Examinons maintenant successivement l'implmentation des couches [dao] et [metier].

7 La couche [dao] de l'application [PAM]Nous nous plaons dans le cadre de l'architecture suivante : 4

Couche [ui] 1

Couche [metier] 2

Couche [dao] 3 7

Objets image de la BD

Interface [JPA]

Implmentation [Hibernate] 5

Couche [JDBC] 6

Spring

7.1

Implmentation

Lectures conseilles : paragraphe 3.1.3 de [ref1] Question : En utilisant l'intgration Spring / JPA, crire les classes [CotisationDao, IndemniteDao, EmployeDao] d'implmentation des interfaces [ICotisationDao, IIndemniteDao, IEmployeDao]. Chaque mthode de classe interceptera une ventuelle exception et l'encapsulera dans une exception de type [PamException] avec un code d'erreur propre l'exception intercepte. Les classes d'implmentation feront partie du paquetage [dao] :

7.2

Configuration

Lectures conseilles : paragraphe 3.1.5 de [ref1] L'intgration Dao / JPA est configure par le fichier Spring [spring-config-dao.xml] et le fichier JPA [persistence.xml] :

http://tahe.developpez.com/java/javaee

35/341

Question : crire le contenu de ces deux fichiers. On supposera que la base de donnes utilise est la base MySQL5 utilise page 18. Le fichier Spring dfinira les trois beans suivants : employeDao de type EmployeDao, indemniteDao de type IndemniteDao, cotisationDao de type CotisationDao. Par ailleurs, l'implmentation JPA utilise sera Hibernate.

7.3

Tests

Maintenant que la couche [dao] est crite et configure, nous pouvons la tester. L'architecture des tests sera la suivante : 4

Couche [tests] 2

Couche [dao] 3 7

Objets image de la BD

Interface [JPA]

Implmentation [Hibernate] 5

Couche [JDBC] 6

Spring

7.3.17.3.1.1

Tests 1InitDB

Lectures conseilles : paragraphes 3.1.6 et 3.1.7 de [ref1]

Nous allons crer deux programmes de tests de la couche [dao]. Ceux-ci seront placs dans le paquetage [dao] [2] de la branche [Test Packages] [1] du projet Netbeans. Cette branche n'est pas incluse dans le projet gnr par l'option [Build project], ce qui nous assure que les programmes de tests que nous y plaons ne seront pas inclus dans le .jar final du projet.

1 2 3

Les classes places dans la branche [Test Packages] ont connaissance des classes prsentes dans la branche [Source Packages] ainsi que des bibliothques de classes du projet. Si les tests ont besoin de bibliothques autres que celles du projet, celles-ci doivent tre dclares dans la branche [Test Libraries] [3]. Ici la bibliothque JUnit est prsente par dfaut en deux versions. Les classes de tests utilisent l'outil de tests unitaires JUnit : [JUnitInitDB] ne fait aucun test. Elle remplit la base de donnes avec quelques enregistrements et affiche ensuite ceux-ci sur la console. [JUnitDao] fait une srie de tests dont elle vrifie le rsultat. Le squelette de la classe [JUnitInitDB] est le suivant :

http://tahe.developpez.com/java/javaee

36/341

1. package dao; 2. 3. ... 4. 5. public class JUnitInitDB { 6. 7. private IEmployeDao employeDao = null; 8. private ICotisationDao cotisationDao = null; 9. private IIndemniteDao indemniteDao = null; 10. 11. @BeforeClass 12. public void init(){ 13. // configuration de l'application 14. ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config-dao.xml"); 15. // couches dao 16. employeDao = (IEmployeDao) ctx.getBean("employeDao"); 17. cotisationDao = (ICotisationDao) ctx.getBean("cotisationDao"); 18. indemniteDao = (IIndemniteDao) ctx.getBean("indemniteDao"); 19. } 20. 21. @Test 22. public void initDB(){ 23. // on remplit la base 24. ... 25. // on affiche le contenu de la base 26. ... 27. } 28. 29. @Before() 30. public void clean(){ 31. // on vide la base 32. ... 33. } 34. }

la mthode [init] est excute avant le dbut de la srie des tests (annotation @BeforeClass). Elle instancie la couche [dao]. la mthode [clean] est excute avant chaque test (annotation @Before). Elle vide la base de donnes. la mthode [initDB] est un test (annotation @Test). C'est le seul. Un test doit contenir des instructions d'assertion Assert.assertCondition. Ici il n'y en aura aucune. La mthode est donc un faux test. Elle a pour rle de remplir la base de donnes avec quelques lignes puis d'afficher le contenu de la base sur la console. Ce sont les mthodes create et findAll des couches [dao] qui sont ici utilises.

Question : complter le code de la classe [JUnitInitDB]. On s'aidera de l'exemple du paragraphe 3.1.6 de [ref1]. Le code gnrera le contenu prsent au paragraphe 2.1, page 7.

7.3.1.2

Mise en oeuvre des tests

Nous sommes dsormais prts pour excuter [InitDB]. Nous dcrivons la procdure avec le SGBD MySQL5 :

http://tahe.developpez.com/java/javaee

37/341

4 2 3 5 1 7

6 8 9

les classes [1] et les fichiers de configuration [2, 3] de la couche [dao] sont mis en place en [4], on ajoute les bibliothques suivantes au projet : celles d'Hibernate qu'on trouve dans [lib/hibernate-tools] celles de Spring qu'on trouve dans [lib/spring] celle du pilote Jdbc de MySQL qu'on trouve dans [lib/divers] en [5] les bibliothques rajoutes au projet le SGBD MySQL5 est lanc. Il doit avoir la base [dbpam_hibernate] avec un utilisateur [dbpam/dbpam] ayant tous les privilges dessus. le projet est construit [6] la classe [JUnitInitDB] est excute [7] la fentre [Test Results] [8] dit que les tests ont t russis. Ce message n'est pas significatif ici, car le programme [JUnitInitDB] ne contient aucune instruction d'assertion Assert.assertCondition, qui pourrait provoquer l'chec du test. Nanmoins, cela montre qu'il n'y a pas eu d'exception l'excution du test.

La fentre [Output] [9] contient les logs de l'excution, ceux de Spring et ceux du test lui-mme. Les affichages faits par la classe JUnitInitDB sont les suivants :1. ------------- Standard Output --------------2. Employs ---------------------3. jpa.Employe[id=5,version=0,SS=254104940426058,nom=Jouveinal,prenom=Marie,adresse=5 rue des oiseaux,ville=St Corentin,code postal=49203,indice=2] 4. jpa.Employe[id=6,version=0,SS=260124402111742,nom=Laverti,prenom=Justine,adresse=La brlerie,ville=St Marcel,code postal=49014,indice=1] 5. Indemnits ---------------------6. jpa.Indemnite[id=5,version=0,indice=1,base heure=1.93,entretien jour2.0,repas jour=3.0,indemnits CP=12.0] 7. jpa.Indemnite[id=6,version=0,indice=2,base heure=2.1,entretien jour2.1,repas jour=3.1,indemnits CP=15.0] 8. Cotisations ---------------------9. jpa.Cotisation[id=3,version=0,csgrds=3.49,csgd=6.15,secu=9.39,retraite=7.88] 10. ------------- ---------------- ---------------

Les tables [EMPLOYES, INDEMNITES, COTISATIONS] ont t remplies. On peut le vrifier avec la connexion Netbeans la base [dbpam_hibernate] dcrite page 20.

http://tahe.developpez.com/java/javaee

38/341

2

1

3

en [1], dans l'onglet [services], on visualise les donnes de la table [employes] de la connexion [dbpam_hibernate] [2] en [3] le rsultat

7.3.27.3.2.1

Tests 2JUnitDao

Nous nous intressons maintenant une seconde classe de tests [JUnitDao] :

Le squelette de la classe sera le suivant :1. package dao; 2. 3. import exception.PamException; 4. ... 5. 6. public class JUnitDao { 7. 8. // couches dao 9. static private IEmployeDao employeDao; 10. static private IIndemniteDao indemniteDao; 11. static private ICotisationDao cotisationDao; 12. 13. @BeforeClass 14. public static void init() { 15. // log 16. log("init"); 17. // configuration de l'application 18. ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config-dao.xml"); 19. // couches dao 20. employeDao = (IEmployeDao) ctx.getBean("employeDao"); 21. indemniteDao = (IIndemniteDao) ctx.getBean("indemniteDao"); 22. cotisationDao = (ICotisationDao) ctx.getBean("cotisationDao"); 23. } 24. 25. @AfterClass 26. public static void terminate() { 27. } 28. 29. @Before() 30. public void clean() { 31. ... 32. } 33.

http://tahe.developpez.com/java/javaee

39/341

34. // logs 35. private static void log(String message) { 36. System.out.println("----------- " + message); 37. } 38. 39. // tests 40. @Test 41. public void test01() { 42. log("test01"); 43. // liste des cotisations 44. List cotisations = cotisationDao.findAll(); 45. int nbCotisations = cotisations.size(); 46. // on ajoute une cotisation 47. Cotisation cotisation = cotisationDao.create(new Cotisation(3.49, 6.15, 9.39, 7.88)); 48. // on la demande 49. cotisation = cotisationDao.find(cotisation.getId()); 50. // vrification 51. Assert.assertNotNull(cotisation); 52. Assert.assertEquals(3.49, cotisation.getCsgrds(), 1e-6); 53. Assert.assertEquals(6.15, cotisation.getCsgd(), 1e-6); 54. Assert.assertEquals(9.39, cotisation.getSecu(), 1e-6); 55. Assert.assertEquals(7.88, cotisation.getRetraite(), 1e-6); 56. // on la modifie 57. cotisation.setCsgrds(-1); 58. cotisation.setCsgd(-1); 59. cotisation.setRetraite(-1); 60. cotisation.setSecu(-1); 61. Cotisation cotisation2 = cotisationDao.edit(cotisation); 62. // vrifications 63. Assert.assertEquals(cotisation.getVersion() + 1, cotisation2.getVersion()); 64. Assert.assertEquals(-1, cotisation2.getCsgrds(), 1e-6); 65. Assert.assertEquals(-1, cotisation2.getCsgd(), 1e-6); 66. Assert.assertEquals(-1, cotisation2.getRetraite(), 1e-6); 67. Assert.assertEquals(-1, cotisation2.getSecu(), 1e-6); 68. // on demande l'lment modifi 69. Cotisation cotisation3 = cotisationDao.find(cotisation2.getId()); 70. // vrifications 71. Assert.assertEquals(cotisation3.getVersion(), cotisation2.getVersion()); 72. Assert.assertEquals(-1, cotisation3.getCsgrds(), 1e-6); 73. Assert.assertEquals(-1, cotisation3.getCsgd(), 1e-6); 74. Assert.assertEquals(-1, cotisation3.getRetraite(), 1e-6); 75. Assert.assertEquals(-1, cotisation3.getSecu(), 1e-6); 76. // on supprime l'lment 77. cotisationDao.destroy(cotisation3); 78. // vrifications 79. Cotisation cotisation4 = cotisationDao.find(cotisation3.getId()); 80. Assert.assertNull(cotisation4); 81. cotisations = cotisationDao.findAll(); 82. Assert.assertEquals(nbCotisations, cotisations.size()); 83. } 84. 85. 86. @Test 87. public void test02(){ 88. log("test02"); 89. // on demande la liste des indemnits 90. ... 91. // on ajoute une Indemnite indemnite 92. .. 93. // on va chercher indemnite en base on rcupre indemnite1 94. .. 95. // on vrifie que indemnite1 = indemnite 96. ... 97. // on modifie l'indemnit obtenue et on persiste la modification en BD. On obtient indemnite2 98. ... 99. // on vrifie la version de indemnite2 100. ... 101. // on va chercher indemnite2 en base on obtient indemnite3 102. ... 103. // on vrifie que indemnite3 = indemnite2 104. ... 105. // on supprime en base l'image de indemnite3 106. ... 107. // on va chercher indemnite3 en base 108. ... 109. // on vrifie qu'on a obtenu une rfrence null 110. ... 111. } 112. 113. @Test 114. public void test03(){ 115. log("test03"); 116. // on rpte un test analogue aux prcdents pour Employe

http://tahe.developpez.com/java/javaee

40/341

117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187.

... } @Test public void test04(){ log("test04"); // on teste la mthode [IEmployeDao].find(String SS) // d'abord avec un employ existant // puis avec un employ inexistant ... } @Test public void test05(){ log("test05"); // on cre deux indemnits avec le mme indice // enfreint la contrainte d'unicit de l'indice // on vrifie qu'une exception de type PamException se produit // et qu'elle a le n d'erreur attendu ... } @Test public void test06(){ log("test06"); // on cre deux employs avec le mme n SS // enfreint la contrainte d'unicit sur le n SS // on vrifie qu'une exception de type PamException se produit // et qu'elle a le n d'erreur attendu ... } @Test public void test07(){ log("test07"); // on cre deux employs avec le mme n SS, le 1er avec create, le 2me avec edit // enfreint la contrainte d'unicit sur le n SS // on vrifie qu'une exception de type PamException se produit // et qu'elle a le n d'erreur attendu ... } @Test public void test08(){ log("test08"); // supprimer un employ qui n'existe pas ne provoque pas d'exception // il est ajout puis dtruit on le vrifie ... } @Test public void test09(){ log("test09"); // modifier un employ sans avoir la bonne version doit provoquer une exception // on le vrifie ... } @Test public void test10(){ log("test10"); // supprimer un employ sans avoir la bonne version doit provoquer une exception // on le vrifie ... } // getters et setters ...

}

Dans la classe de tests prcdente, la base est vide avant chaque test. Question : crire les mthodes suivantes : - test02 : on s'inspirera de test01 - test03 : un employ a un champ de type Indemnite. Il faut donc crer une entit Indemnite et une entit Employe - test04.

http://tahe.developpez.com/java/javaee

41/341

7.3.2.2

Mise en oeuvre des tests

En procdant de la mme faon que pour la classe de tests [JUnitInitDB], on obtient les rsultats suivants :

1

2

en [1], on excute la classe de tests en [2], les rsultats des tests dans la fentre [Test Results]

Provoquons une erreur pour voir comment cela est signal dans la page web des rsultats :1. @Test 2. public void test01() { 3. log("test01"); 4. // liste des cotisations 5. List cotisations = cotisationDao.findAll(); 6. int nbCotisations = cotisations.size(); 7. // on ajoute une cotisation 8. Cotisation cotisation = cotisationDao.create(new Cotisation(3.49, 6.15, 9.39, 7.88)); 9. // on la demande 10. cotisation = cotisationDao.find(cotisation.getId()); 11. // vrification 12. Assert.assertNotNull(cotisation); 13. Assert.assertEquals(0, cotisation.getCsgrds(), 1e-6); 14. Assert.assertEquals(6.15, cotisation.getCsgd(), 1e-6); 15. Assert.assertEquals(9.39, cotisation.getSecu(), 1e-6); 16. Assert.assertEquals(7.88, cotisation.getRetraite(), 1e-6); 17. // on la modifie 18. .... 19. }

Ligne 13, l'assertion va provoquer une erreur, la valeur de Csgrds tant 3.49 (ligne 8). L'excution de la classe de tests donne les rsultats suivants :

1 2

la page des rsultats [1] montre maintenant qu'il y a eu des tests non russis [2]. en [3], un rsum de l'exception qui a fait chouer le test. On y trouve le n de la ligne du code Java o s'est produite l'exception.

http://tahe.developpez.com/java/javaee

42/341

8 La couche [metier] de l'application [PAM]Maintenant que la couche [dao] a t crite, nous passons l'tude de la couche mtier [2] : 4

Couche [ui] 1

Couche [metier] 2

Couche [dao] 3 7

Objets image de la BD

Interface [JPA]

Implmentation [Hibernate] 5

Couche [JDBC] 6

Spring

8.1

L'interface Java [IMetier]

Celle-ci a t dcrite au paragraphe 5, page 29. Nous la rappelons ci-dessous :1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. package metier; import java.util.List; import jpa.Employe; public interface IMetier { // obtenir