Aller au contenu

Présentation du TD⚓︎

Dans les TD5 et TD6, nous avons vu comment mettre en place une architecture 3 tiers de ce type :

archi 3-tiers

Architecture 3-tiers (TD5 & TD6)

Notre application est fonctionnelle, mais comme nous l'avions indiqué au tout début de ce cours, il faut toujours penser en terme de réutilisabilité. On peut imaginer qu'une autre application Web souhaite également accéder aux mêmes services métiers. De même, on pourrait souhaiter qu'un client lourd (une application Java "classique" par exemple) puisse également le faire.

De même que les Servlets permettent à un navigateur Web de se connecter à l'application JEE, il existe un autre objet JEE permettant à une application Java de se connecter à des services métiers à distance. Ce sont les EJB, pour Entreprise JavaBeans.

Ils vont nous permettre de mettre en place une architecture 3-tiers ou 4-tiers de ce type (les couches "présentation" et "métier" pourront toujours être sur le même serveur, comme précédemment, ou, ce qui est nouveaux, sur des serveurs différents) :

archi td4

Architecture 4-tiers

Cela permet à différentes applications Web et différents clients lourds Java de se connecter aux services métiers proposés :

archi td4 avec plusieurs applications clientes

Architecture 4-tiers avec plusieurs applications clientes

1. Rappel sur l'architecture client/serveur⚓︎

Une architecture client serveur est constituée de 2 programmes et d'un protocole :

  1. Un programme client qui effectue une requête (il pose une question).
  2. Un programme serveur qui propose des services (il effectue des traitements pour répondre à cette question).
  3. Un protocole (c'est la façon dont les deux programmes vont communiquer).

archi td4

Architecture client serveur
Pour les Servlets

Dans le cas des servlets, on avait :

  1. Le programme client est le navigateur.
  2. Le programme serveur est la Servlet.
  3. Le protocole de communication est HTTP.
Pour les EJB

Dans le cas des EJB, nous allons avoir :

  1. Le programme client est le client lourd Java ou la couche "présentation" (i.e. la Servlet).
  2. Le programme serveur est l'EJB.
  3. Le protocole de communication est RMI, pour Remote Method Invocation (Appel de Méthodes à Distance en français) (nécessaire en fait uniquement si le client et le serveur sont sur des JVM différentes).

2. Les EJBs⚓︎

Présentation

De même que le cycle de vie des Servlets (naissance / attente de requête HTTP / destruction) était géré par le conteneur de Servlets disponible sur le serveur Web, le cycle de vie des EJBs est géré par un conteneur d'EJB.

Tomcat et WildFly

À nouveau, Tomcat fourni uniquement un conteneur de Servlets. Pour utiliser des EJBs, il faut obligatoirement utiliser un serveur d'application. Nous allons à nouveau utiliser WildFly.

Les EJBs

Il existe trois types d'EJBs :

  1. Les EJB entités : C'est exactement ce que nous avons utilisé, sans le dire, avec les entités JPA (ce sont des beans classiques).
    On utilise l'annotation @Entity pour les définir (ce que nous avons fait dans le TD précédent).
  2. Les EJB sessions : C'est eux qui vous nous permettre d'appeler les services métiers depuis l'extérieur (c'est en fait de ces EJBs dont on parle depuis le début de ce TD).
    On utilise 3 annotations différentes pour les définir - @Singleton, @Stateless et @Statefull - Cf. ci-dessous.
  3. Les EJB messages : Nous n'allons pas les utiliser ici. Ils permettent d'appeler des traitements asynchrones.
Les EJBs sessions

Il y trois possibilités :

  • @Singleton : Cela signifie qu'il n'y a qu'un seule instance de cette classe. Tous les clients effectuant des requêtes partagent donc la même.
  • @Stateless : Cela signifie que les échanges (c'est-à-dire les requêtes) se feront sans état, c'est-à-dire sans mémoire. Cela ressemble beaucoup à @Singleton, mais la différence est que le serveur peut décider de créer de nouvelles instances de la classe s'il y a trop de clients en même temps.
  • @Statefull : Cela signifie que les échanges se feront avec mémoire. L'historique des requêtes effectuées par un client est conservé. Concrétement, chaque client dispose de sa propre instance de la classe. On peut donc avoir des variables de classe pour conserver des données en mémoire entre les requêtes.

Cycle de vie

Voici à quoi ressemble le cycle de vie d'un EJB session, de la manière dont nous allons l'utiliser :

sequenceDiagram
    participant Client (Servlet)
    participant Conteneur d'EJB
    participant EJB Session
    participant Service de transaction (JTA)
    Client (Servlet) ->> Conteneur d'EJB: 1. Appel
    Conteneur d'EJB  ->> Service de transaction (JTA): 2. begin Transaction
    Conteneur d'EJB  ->> EJB Session: 3. Appel
    EJB Session  ->> EJB Session: 4. Traitement
    EJB Session  -->> Conteneur d'EJB: 5. Résultat ou Exception
    Conteneur d'EJB  ->> Service de transaction (JTA): 6. commit ou rollback
    Conteneur d'EJB  -->> Client (Servlet): 7. Résultat ou Exception

Par rapport à ce diagramme, il nous suffit d'implémenter le point 4 : on appelle le service DAO qui convient. Tout le reste est géré par le framework.

Ce que nous avons fait dans le TD3

Ce que nous avons fait précédemment ressemblait beaucoup à cela, mais nous devions gérer les transaction en plus. Nous avions en fait implémenté ce cycle de vie :

sequenceDiagram
    participant Client (Servlet)
    participant Business et DAO
    participant Service de transaction (JTA)
    Client (Servlet) ->> Business et DAO: 1. Appel
    Business et DAO  ->> Service de transaction (JTA): 2. begin Transaction
    Business et DAO  ->> Business et DAO: 3. Traitement
    Business et DAO  ->> Service de transaction (JTA): 4. commit ou rollback
    Business et DAO  -->> Client (Servlet): 5. Résultat ou Exception

Dans ce diagramme, il fallait implémenter tous les points :

  1. Instanciation de l'objet NotesBusinessImpl depuis la méthode init des Servlets.
  2. Éxécution de em.getTransaction().begin(); depuis le DAO.
  3. Éxécution de la requête (avec persist par exemple).
  4. Éxécution de em.getTransaction().commit(); ou em.getTransaction().rollback(); depuis le DAO.
Création d'un EJB session

Concrètement, un EJB est une classe qui implémente deux interfaces :

  • Une interface locale, qui liste les services disponibles pour un appel local de l'EJB (i.e. depuis la même JVM).
    On utilise l'annotation @Local.
  • Une interface distante, qui liste les services disponibles pour un appel à distance de l'EJB (i.e. depuis une autre JVM, éventuellement sur un autre serveur). On utilise l'annotation @Remote.

On peut donc très facilement choisir de ne pas déployer les mêmes services pour les accès en local ou à distance, alors qu'il n'y a qu'une seule implémentation.

3 projets Java

Pour pouvoir définir des EJBs (sessions), il faut un projet Java EJB. Notre projet ne sera donc plus implémenté dans un seul projet Web dynamique, mais il va nous falloir trois projets :

  1. Un projet Web dynamique pour la couche présentation.
    Un tel projet est déployé sur un serveur via un WAR (pour Web Application Archive).
  2. Une projet EJB pour la couche métier.
    Un tel projet est déployé sur un serveur via un JAR (pour Java Archive).
  3. Une projet application d'entreprise qui va contenir ces deux modules.
    Un tel projet est déployé sur un serveur via un EAR (pour Entreprise Application Archive).
    Sur le serveur Wildfly, nous ne déploierons en fait que ce projet.

    Il va en fait même nous falloir un 4e projet :
  4. Un projet java classique, pour représenter le client lourd.
    Ce projet ne sera pas déployé sur le serveur.

Nous allons maintenant implémenter cette architecture 4-tiers, plus précisément, nous allons implémenter le schéma suivant :

Architecture TD4

Schéma de l'architechture du TD7 (4-tiers)