Une application JEE nécessite un environnement assez complexe à comprendre et à construire. La première chose dont ce type d'application a besoin pour fonctionner est un serveur d'application. Là où une application web n'avait besoin que d'un serveur Tomcat (ou autre), une application entreprise doit fonctionner dans un serveur d'applications, plus important, et plus complexe. D'ailleurs, la plupart des serveurs d'application intègrent un serveur Tomcat en tant que module, pour gérer leurs applications web.

Un serveur d'application est un élément logiciel, qui formellement ressemble à un serveur Tomcat. La différence est qu'il expose plus de fonctionnalités, et est capable de fournir de nombreux services. Citons-en ici quelques-uns :

  • Il possède un module d'annuaire, appelé JNDI (Java Naming Directory Interface), qui enregistre toutes les ressources que ce serveur gère et expose. Lorsque l'on a besoin d'un ressource particulière, on peut la demander à l'annuaire, à partir de son nom.

  • Il permet de gérer des EJB (Enterprise Java Beans), que nous allons voir en détails dans la suite de ce chapitre.

  • Il permet de gérer des applications web, et de répondre aux requêtes HTTP sur le port 80 (entre autres).

  • Il est capable de se connecter à des bases de données, et d'exposer ces connexions sous forme de data sources . Il gère les transactions, distribuées ou non, de ces bases.

  • Il sait gérer des files d'attentes de messages, qu'il peut ensuite redistribuer à des abonnés (Java Messaging System).

  • Il peut se connecter à un service de messagerie ( mail ), et d'exposer ce service dans son annuaire.

  • Il gère la journalisation de tous ces éléments, de même que le suivi des performances, et différentes fonctions de monitoring .

  • Enfin, il a une vision globale de tous les composants qu'il gère, et il est capable de les faire dialoguer les uns avec les autres, notamment sous forme d'injection de dépendances.

Sans entrer dans les détails de ce qu'est un EJB, disons simplement que techniquement, un EJB est une interface et une classe qui implémente cette interface. De plus, un EJB est géré par un serveur d'application (ici Glassfish), qui l'expose au travers de son annuaire JNDI.

Les implémentations de nos EJB sont entièrement gérées par Glassfish, nous allons donc les ranger dans le projet cours-ear-ejb. En revanche, nos interfaces vont être utilisées par d'autres modules de notre application, non gérés par Glassfish. Nous allons donc les ranger dans un autre module. On crée pour cela un nouveau projet, de type Java > Java application, et on le nomme cours cours-ear-ejb-interfaces.


Ce module est pour le moment indépendant de notre application. Créons une première interface dans ce projet, appelée MarinService. Notre projet ressemble alors à la figure suivante.


Le code de notre interface est pour le moment minimaliste !


Qu'est-ce qui différencie l'interface d'un EJB d'une interface normale ? La réponse tient en un seul mot : rien.

Créons à présent l'implémentation de cet EJB. Netbeans propose un processus automatique de création d'EJB, mais il ne nous convient pas, car il ne permet pas de créer un EJB qui implémente l'interface que nous venons d'écrire.

Dans un premier temps, il faut mettre notre module cours-ear-ejb-interfaces en dépendance du module cours-ear-ejb. Pour cela, il faut ouvrir les propriétés du projet cours-ear-ejb, et cliquer sur le bouton Add project... dans l'onglet Librairies. Il n'y a plus qu'à sélectionner le projet cours-ear-ejb-interfaces et à valider.


Il n'y a plus qu'à créer une classe dans ce projet, appelons-la MarinServiceImpl.


Cette classe MarinServiceImpl doit implémenter l'interface MarinService. De plus, pour en faire un EJB, il faut l'annoter. L'EJB que nous allons écrire est un EJB stateless , il doit donc porter l'annotation @Stateless. Il existe aussi des EJB stateful , que l'on annote avec @Stateful.

La deuxième annotation que nous ajoutons est @Remote, et nous lui donnons l'interface implémentée en paramètre. Nous aurions pu mettre cette annotation sur notre interface MarinService, mais cela nous aurait obligé à créer une dépendance de notre module d'interfaces vers la librairie JEE qui définit les annotations. Cette façon de faire est donc plus légère.

Le code final de notre classe d'implémentation est le suivant.


L'argument de l'annotation @Stateless est destiné à l'annuaire du serveur qui va gérer cet EJB. Il indique le nom de cet EJB dans l'annuaire. On peut l'omettre, dans ce cas un nom par défaut est choisi.

On constate que Netbeans a bien pris cette classe comme un EJB : il apparaît maintenant sous son nom dans le nœud Enterprise beans de notre projet cours-ear-ejb.

Pour le moment notre EJB ne fait pas grand chose : il n'expose qu'une seule méthode, qui retourne systématiquement -1. Mais il est suffisant pour terminer de créer l'environnement technique dans lequel il va vivre.

Une EJB est comme une servlet : une fois lancé, rien ne se passe, et il faut créer une application cliente pour la voir en action. Dans le cas d'une servlet ou d'une page JSP, l'application cliente est un navigateur web. Dans le cas d'un EJB, le client est une méthode main() qu'il faut écrire à la main.

Cette méthode doit faire trois choses :

  • Elle doit se connecter à l'annuaire du serveur d'application. L'ouverture de cette connexion requiert des dépendances spécifiques à chaque serveur d'application.

  • Une fois connectée, elle doit interroger l'annuaire avec le nom de la ressource dont elle a besoin. Si cette ressource existe bien, l'annuaire retourne un objet qui implémente l'interface associée à cette ressource.

  • Une fois en possession de cet objet, il suffit d'invoquer ses méthodes pour y accéder. Ici cet objet implémentera notre interface MarinService, nous pourrons donc invoquer sa méthode createMarin(String), et vérifier qu'elle nous retourne bien -1.

Pour porter ce code client, on crée un projet supplémentaire dans Netbeans, appelé cours-ejb-client. Ce projet a besoin de deux dépendances :

  • une dépendance vers le projet d'interfaces, puisqu'il va utiliser l'interface MarinService ;

  • une dépendance vers des éléments de Glassfish : glassfish-naming.jar, gf-client.jar et glassfish-corba-orb.jar.

Ces trois derniers JARs se trouvent dans $GLASSFISH_HOME/modules.

Pour pouvoir se connecter à l'annuaire d'un serveur d'application, une application cliente a besoin d'un certain nombre d'informations, qui sont fixées de façon standard dans des variables d'environnement. La façon la plus simple de spécifier ces variables est de les écrire dans un fichier de propriétés standard : jndi.properties, qui doit se trouver à la racine de notre application cliente. Voyons le contenu de ce fichier dans le cas de Glassfish.


Le code suivant va alors être capable de se connecter à notre EJB.


La structure de notre projet cours-ejb-client est la suivante.


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