3. Mise en oeuvre du pattern session facade

3.1. Introduction

Le pattern session facade est celui qui définit la façon dont on accède à un modèle d'objets persistants dans un environnement JEE5. D'une façon générale, tous les patterns de programmation qui portent le nom facade sont écrits dans la même idée : masquer la complexité technique d'une suite d'opérations, et les rendre accessibles en un appel de méthode unique. Une façade agit donc comme une enveloppe, et expose des fonctionnalités simples clairement définies. Une EJB session facade est donc un EJB stateless , qui connaît notre modèle objet, connaît notre unité de persistance, et expose les opérations CRUD de manipulation de nos données, en plus d'opérations plus complexes, prédéfinies.

3.2. Modèle objet

Enrichissons notre exemple simple du chapitre précédent, afin d'illustrer ce concept. Notre modèle sera particulièrement simple, il ne comportera qu'une unique classe : Marin. Afin de porter cette classe, on crée un nouveau projet Netbeans, cours-ejb-model. Ce projet est un projet Java classique, il ne définit pas d'unité de persistence, nous verrons pourquoi dans la suite. Voici sa structure.
Structure du projet modèle

Figure 37. Structure du projet modèle


Donnons ici le code de notre classe Marin. Il s'agit d'une entité JPA classique.

Exemple 60. Classe Marin du modèle

package org.paumard.ejb.model ;

 @Entity
 public  class Marin  implements Serializable {

     private  static  final  long serialVersionUID =  1L;

     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;

     private String nom ;
    
     // reste de la classe
}

Notons que le projet cours-ejb-model doit avoir une dépendance vers EclipseLink, puisque la classe Marin porte des annotations JPA. Nous n'avons pas encore décrit la structure d'un fichier EAR. Disons pour le moment qu'il s'agit d'une archive, au même sens qu'un fichier JAR ou WAR, qui possède une structure interne spéciale. Notamment, le standard EAR exige que seuls les JAR contenant des EJB peuvent être rangés à la racine de cette archive, tous les autres JAR doivent être rangés dans un sous-répertoire lib de ce fichier EAR. C'est donc dans ce répertoire que le JAR de ce projet devra être rangé au final.

3.3. Définition de l'unité de persistance

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.
Structure du projet de persistence

Figure 38. Structure du projet de persistance


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.

3.3.1. Définition d'une source de données

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.
Création d'une source de données via Netbeans

Figure 39. Création d'une source de données via Netbeans


On choisit alors l'option JDBC Resources, dans l'onglet Glassfish, comme sur la figure suivante.
Sélection d'une ressource JDBC

Figure 40. Sélection d'une ressource JDBC


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.
Création de la source de données

Figure 41. Création de la source de données


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.
Définition d'une réserve de connexions

Figure 42. Définition d'une réserve de connexions


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.

3.3.2. Fichier persistence.xml

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.

Exemple 61. Fichier persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
 <persistence  version="2.0"  xmlns="http://java.sun.com/xml/ns/persistence" 
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
                                 http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

     <persistence-unit  name="cours-ear-pu"  transaction-type="JTA">

         <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

         <jta-data-source>jdbc/CoursEJBDS</jta-data-source>
	
         <class>org.paumard.ejb.model.Marin</class>
	
         <properties>
             <property  name="eclipselink.ddl-generation"  value="drop-and-create-tables"/>
         </properties>
    
     </persistence-unit>
    
 </persistence>

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.

3.4. Assemblage de notre application

Nous avons donc maintenant cinq modules dans notre projet.
Structure des cinq modules

Figure 43. Structure des cinq modules


  • 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.
Assemblage final de l'EAR

Figure 44. Assemblage final de l'EAR


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

3.5. Assemblage et déploiement

L'assemblage final de cet EAR est lancé en sélectionnant l'option Clean and Build du menu contextuel du nœud du projet cours-ear. Lorsque l'on lance cette opération, Netbeans lance un certain nombre de scripts, finit par annoncer que l'opération s'est correctemet déroulée. Le résultat est un fichier .ear, rangé dans le répertoire dist de notre projet. La structure de ce fichier doit exactement suivre celle de la répartition de nos modules dans l'application. Le déploiement dans Glassfish se fait en invoquant l'option Deploy du même menu. L'EAR est alors pris en compte par Glassfish, qui va déployer les EJB, initialiser la source de données, charger l'unité de persistance, et créer la structure de base de données en conséquences. De la même façon, cette opération doit se terminer par l'apparition d'un message de victoire dans la console. En cas de problème de déploiement, il peut être assez difficile de diagnostiquer ce qui ne va pas. Un point de départ peut être le contenu du répertoire cours-ear/cours-ear/dist. Ce répertoire contient deux choses. Tout d'abord le fichier EAR déployé par Glassfish. Ensuite l'ouverture de ce fichier par Glassfish, rangée dans le sous-répertoire gfdeploy. Examiner le contenu de ces deux éléments peut permettre de détecter des problèmes d'assemblage, et de les corriger.

3.6. Utilisation du client

L'utilisation du client n'a pas changé. Tout ce qui a été vu sur ce point dans le chapitre précédent est toujours valide.
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