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.
2.2. Installation dans Glassfish à l'aide de Netbeans
De même que pour la partie JPA, nous allons utiliser Netbeans 6.9.1 pour cette présentation.
La première étape consiste à créer un projet Java EE > Enterprise application. Nous verrons les détails du packaging de ce projet dans la suite. Pour le moment, disons simplement que notre modèle JPA et nos EJB seront des modules de ce projet.
Le deuxième étape consiste à donner un nom à ce projet, que nous appellerons "cours-ear".
La dernière étape est importante : c'est elle qui donne le serveur d'application cible, et la version de JEE que l'on va utiliser. Ici, on sélectionne Glassfish v3, et JEE5, au lieu de JEE6 qui est sélectionné par défaut. On décochera également la création de l'application web, que nous écrirons dans un deuxième temps.
La structure du projet créé par Netbeans est la suivante.
2.3. Création d'un premier EJB
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 !
Exemple 56. Une première interface d'EJB
package org.paumard.ejb.service ;
public interface MarinService {
public long createMarin(String nom) ;
}
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.
Exemple 57. Une première implémentation d'un EJB
package org.paumard.ejb.service.impl ;
@Stateless(mappedName="MarinService")
@Remote(MarinService.class)
public class MarinServiceImpl implements MarinService {
@Override
public long createMarin(String nom) {
return -1L ;
}
}
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.
2.4. Déploiement de notre premier EJB
Déployer un EJB consiste à construire un fichier archive EAR (Enterprise Application Archive), analogue aux fichiers WAR des applications web, dans un serveur d'application. De même que pour le fichier WAR, le fichier EAR a une structure particulière et spécifiée dans le standard JEE.
Ce fichier EAR est géré par le module maître de notre application cours-ear. Pour que cet EAR fonctionne, il faut lui dire qu'il doit prendre en dépendance le projet cours-ear-ejb-interfaces. Il faut pour cela faire deux choses :
-
ajouter ce projet en dépendance du projet cours-ear dans l'onglet Librairies des propriétés de ce projet ;
-
ajouter ce projet dans l'onglet packaging, en précisant qu'il doit aller dans le répertoire
lib
.
On remarque sur cette deuxième figure que le projet d'interfaces se trouve bien dans le répertoire
lib
, que l'on peut changer dans l'interface de NetBeans en double-cliquant dessus.
Une fois ces deux opérations menées à bien, il suffit de lancer le projet EAR. Deux onglets s'ouvrent alors dans Netbeans : le premier correspond au fichier de journalisation de Glassfish, et le second nous indique que notre EAR a été correctement déployé.
2.5. Création d'un client
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.
Exemple 58. Fichier
jndi.properties
dans le cas de Glassfish
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
java.naming.factory.url.pkgs=com.sun.enterprise.naming
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl
Le code suivant va alors être capable de se connecter à notre EJB.
Exemple 59. Une première connexion à un EJB
public class CheckEJB {
public static void main(String... args) throws NamingException {
InitialContext context = new InitialContext() ;
MarinService marinService = (MarinService)context.lookup("MarinService") ;
long id = marinService.createMarin("Surcouf") ;
System.out.println("Id = " + id) ;
}
}
La structure de notre projet cours-ejb-client est la suivante.