Où doit-on placer notre fichier persistence.xml, celui dans lequel nous devons définir notre unité de persistance ? On a en fait plusieurs choix. Soit l'ensemble des classes de notre modèle est rangé dans le même JAR, et dans ce cas, le plus simple est de ranger ce fichier dans le répertoire META-INF de JAR. Soit les entités JPA de notre modèle sont réparties dans plusieurs JAR (ce qui est parfaitement légal), auquel cas, le plus logique est de le ranger dans le répertoire META-INF de son propre JAR, de façon à ne pas privilégier un JAR du modèle plutôt qu'un autre. C'est cette façon de faire que nous choisissons ici, aussi pour traiter par l'exemple un cas de configuration non trivial.

Créons donc un projet cours-ejb-persistence, qui ne porte que ce fichier persistence.xml. Voici sa structure.


On ne définit pas une unité de persistance dans un contexte JEE de la même façon que dans un contexte JSE, comme nous l'avons fait au chapitre précédent.

Comme nous l'avons déjà vu, un serveur d'application quel qu'il soit, sait se connecter à des bases de données, et expose ses connexions dans son annuaire au travers d'objets de type DataSource. Lorsqu'un module d'une application entreprise a besoin d'accéder à une base de données, en aucun cas elle n'ouvre la connexion à cette base elle-même : elle utilise plutôt l'une de ces sources de données, en l'appelant par son nom. C'est ce que fait notre unité de persistance, qui, plutôt que de définir les coordonnées d'une connexion JDBC, comme nous l'avons fait au chapitre précédent, va référencer une source de données existante, définie au niveau de notre serveur d'applications.

On peut définir une telle source de données en utilisant Netbeans. Pour cela, il faut aller dans le menu New... > Other... du nœud Server Resources de notre projet cours-ear.


On choisit alors l'option JDBC Resources, dans l'onglet Glassfish, comme sur la figure suivante.


La fenêtre suivante nous demande deux choses.

  • La réserve de connexions JDBC sur laquelle cette source de données va s'appuyer. Effectivement, plutôt que de ne fonctionner qu'avec une connexion unique, les sources de données s'appuient sur des réserves de connexions, ouvertes à la demande, et fermées automatiquement si elles ne sont pas utilisées.

  • Le nom de cette source de données dans l'annuaire (JNDI) du serveur d'applications. On choisira jdbc/CoursEJBDS comme nom, c'est par ce nom que notre unité de persistance pourra se connecter à la base.


La fenêtre suivante nous propose d'entrer des propriétés supplémentaires, et dans cet exemple nous n'en avons pas.

Ensuite nous passons à la définition de notre réserve de connexions. Cette réserve est une ressource enregistrée dans l'annuaire, elle doit donc porter un nom. On doit également lui définir une connexion à une base de données. Pour cela, Netbeans nous propose les connexions qu'il connait.


Les deux dernières étapes permettent de revoir les choix, et éventuellement de les modifier. À l'issue de ce processus, un fichier sun-ressources.xml est créé dans notre projet cours-ear, dans le nœud Server resources.

Malheureusement, vue la structure de modules que l'on a choisie pour déployer notre projet, les wizards automatiques de Netbeans ne vont pas nous permettre de générer le fichier persistence.xml. Voici donc son contenu.


Deux éléments ont changé dans ce fichier, par rapport à celui que l'on avait écrit dans le chapitre précédent.

  • Tout d'abord l'attribut transaction-type de l'élément persitence-unit a la valeur JTA. Cela signifie que les transactions de cette unité de persitance seront gérées par le serveur d'application, et non plus à la main. Nous verrons les conséquences de ce point dans la suite.

  • On voit apparaître un élément jta-data-source. Cet élément porte le nom de la source de données que l'on vient de créer. Notre unité de persistance se connectera à la base en utilisant cette source de données.

Le reste du fichier ne change pas, mis à part que l'on n'a plus besoin des propriétés que JDBC utilisait pour se connecter à la base.

Nous avons donc maintenant cinq modules dans notre projet.


  • cours-ear est notre projet maître, c'est lui qui sera déployé dans Netbeans. Le module cours-ear-ejb est un de ses sous-modules, il le possède donc automatiquement en dépendance. Il définit en plus des dépendances vers les trois autres modules : cours-ear-ejb-interfaces, cours-ejb-model et cours-ejb-persistence. Il dépend également d'EclipseLink.

  • cours-ear-ejb porte l'implémentation de nos EJB. Ce module dépend des modules cours-ejb-model et cours-ear-ejb-interfaces. Pour le moment l'implémentation de nos EJB ne dépend pas effectivement de notre modèle, mais ce point va changer.

  • cours-ear-ejb-interfaces porte les interfaces implémentées par nos EJB. Ce module dépend du module cours-ejb-model, et d'EclipseLink.

  • cours-ejb-model porte nos classes persistantes, et ne dépend que d'EclipseLink.

  • cours-ejb-persistence ne porte que notre unité de persistance, déclarée dans le fichier persistence.xml. Comme ce module ne porte pas de code, il ne dépend de rien.

  • Le module cours-ejb-client est particulier. Il ne fait pas partie de notre application d'entreprise, mais c'est lui qui sera utilisé pour y accéder.

Notre application entreprise est maintenant prête à être assemblée. La définition de cet assemblage se fait dans les propriétés de ce module, dans l'onglet Packaging.


On notera que tous les JARS en dépendance sont rangés dans le répertoire lib de cet EAR.

JPA & EJB
Retour au blog Java le soir
Cours & Tutoriaux

Table des matières

Introduction
1. Objet du mapping objet / relationnel
2. Un peu d'histoire
Un premier exemple
1. Introduction
2. Création de l'environnement technique
2.1. Introduction
2.2. Création de la base Derby
2.3. Création du projet NetBeans et d'une première entité
2.4. Structure d'un projet persistant
2.5. Une première classe persistante
2.6. Un premier fichier persistence.xml
3. Utilisation de ce premier exemple
3.1. Écriture du code d'utilisation
3.2. Exécution de notre premier exemple
3.3. Modification de la class Marin
3.4. Opérations CRUD
Mettre un jeu de classes en base
1. Introduction
2. Définition d'une entité JPA
2.1. Écriture de l'entité
2.2. Annotation de l'entité
2.3. Annotations des champs
2.4. Exemple d'utilisation
3. Opérations sur les entités
3.1. Introduction
3.2. Opération PERSIST
3.3. Opération REMOVE
3.4. Opération REFRESH
3.5. Opération DETACH
3.6. Opération MERGE
4. Mise en relation d'entités
4.1. Introduction
4.2. Relations unidirectionnelles et bidirectionnelles
4.3. Relation 1:1
4.4. Relation 1:p
4.5. Relation p:1
4.6. Relation n:p
4.7. Comportement cascade
4.8. Effacement des entités orphelines
5. Charger des entités et leurs relations
6. Objets inclus
6.1. Introduction
6.2. Déclaration d'un objet inclus
6.3. Utilisation d'objets inclus
6.4. Cas où l'objet inclus est nul
6.5. Renommer les colonnes incluses
6.6. Collections d'objets inclus
L'API Collection en base
1. Introduction
2. Enregistrer une collection d'entités
2.1. Enregistrement d'une collection simple
2.2. Enregistrement d'un Set
2.3. Enregistrement d'une List
3. Enregistrer une collection de types de base
4. Enregistrement d'une Map
4.1. Table de hachage de type (type de base, entité)
4.2. Cas où la clé est un champ de la valeur
4.3. Cas d'une table (entité, entité)
Héritage
1. Introduction
2. Enregistrement d'une hiérarchie de classes
2.1. Entité et super-classe non enregistrée
2.2. Position du problème
2.3. Trois façons de faire
3. Stratégie SINGLE_TABLE
3.1. Fonctionnement
3.2. Mise en place
3.3. Limitations
4. Stratégie JOINED
4.1. Fonctionnement
4.2. Mise en place
4.3. Limitations
5. Stratégie TABLE_PER_CLASS
5.1. Fonctionnement
5.2. Mise en place
5.3. Limitations
Requêtes
1. Introduction
2. Un premier exemple
2.1. Écriture d'une première requête
2.2. Exécution d'une première requête
2.3. Exécution d'une première requête d'agrégation
3. Définition de requêtes
3.1. Requêtes dynamiques
3.2. Requêtes paramétrées
3.3. Requêtes nommées
3.4. Requêtes natives
4. Exécution, analyse du résultat
4.1. Exécution d'une requête dynamique
4.2. Exécution d'une requête nommée
4.3. Analyse du résultat
4.4. Cas des résultats de grande taille
4.5. Remarques
5. Clause From
5.1. Définition des entités
5.2. Jointures dans la clause From
5.3. Remarque finale sur les jointures en JPQL
6. Clause Where
6.1. Variables et chemins dans une clause where
6.2. Expressions conditionnelles et opérateurs
6.3. Requêtes imbriquées
6.4. Opérateurs any, all et some
6.5. Expressions fonctionnelles
7. Clauses Group By et Having
8. Opérations Update et Delete
EJB
1. Introduction
2. Un premier exemple
2.1. Introduction
2.2. Installation dans Glassfish à l'aide de Netbeans
2.3. Création d'un premier EJB
2.4. Déploiement de notre premier EJB
2.5. Création d'un client
3. Mise en oeuvre du pattern session facade
3.1. Introduction
3.2. Modèle objet
3.3. Définition de l'unité de persistance
3.4. Assemblage de notre application
3.5. Assemblage et déploiement
3.6. Utilisation du client
4. Opération de persistance en façade
4.1. Introduction
4.2. Enrichissement du service
4.3. Création de la méthode findMarinById(long)
4.4. Ajout de la méthode findAllMarins()
4.5. Utilisation dans un code client
5. Types d'EJB
5.1. Introduction
5.2. Qu'est-ce qu'un EJB ?
5.3. Écriture d'un EJB session
5.4. Qu'est-ce qu'une méthode métier ?
5.5. EJB avec ou sans état
5.6. Gestion des transactions
5.7. Restrictions
6. Cycle de vie d'un EJB
6.1. Cas des EJB sans état
6.2. Cas des EJB avec état
6.3. Injection de dépendances
7. Transaction gérée par l'EJB
7.1. Introduction
7.2. Déclaration du mode transactionnel
7.3. Gestion de la transaction
7.4. Fonctionnement de la transaction
7.5. Cas des EJB avec état
8. Transaction gérée par le serveur
8.1. Introduction
8.2. Déclaration du mode transactionnel
8.3. Gestion de la transaction
8.4. Fonctionnement de la transaction
8.5. Remarques
9. Intercepteurs
9.1. Introduction
9.2. Aperçu général
9.3. Cycle de vie d'un intercepteur
9.4. Object InvocationContext
9.5. Interception d'un EJB ou d'une méthode métier
9.6. Exemple de mise en œuvre d'un intercepteur