Vous êtes sur la page 1sur 128

ROYAUME DU MAROC

Université Cadi Ayyad


Ecole Nationale des Sciences Appliqués
Département Génie Informatique, Réseaux & Télécoms
Safi
____________

JAVA EE

oujaoura@gmail.com Mustapha OUJAOURA


Chap: EJB
• Introduction
Introduction & Historique
3

¨ Ecrit dans le langage de programmation Java, un Bean Entreprise (EJB) est un


composant côté serveur qui encapsule la logique métier d'une application.
¨ Historique rapide du développement de la spécification EJB :
¤ Mars 1998 (EJB 1.0) : une première spécification assez « légère » voit le
jour. Seuls les Sessions Beans existaient.
¤ Novembre 1999 (EJB 1.1) : des fonctionnalités comme la sécurité, les
Entity Beans (simpliste) ont été ajoutés.
¤ Août 2001 (EJB 2) : suite aux problèmes de performances, les interfaces
locales ont été créées. La spécification EJB 2 intègre également la
première version de l’EJB-QL (limité), les relations entre Entity Beans et les
Message Driven Beans.
¤ Novembre 2003 (EJB 2.1) : des modifications mineures ont été effectuées
autour de EJB-QL. L’EJB Timer Service est ajouté.
¤ Mai 2006 (EJB 3): la refonte complète de la spécification J2EE, et plus
particulièrement des EJB. C’est le début de Java EE 5 et des EJB 3,
¤ ….
Les Beans Enterprise
4

¨ Les beans Enterprise simplifient le développement d'applications


volumineuses et distribuées:
¤ Le conteneur EJB fournit des services de niveau système aux beans d'entreprise, le
développeur de beans peut alors se concentrer sur la résolution des problèmes
métier de l'entreprise. Le conteneur EJB est responsable des services au niveau du
système, tels que la gestion des transactions et les autorisations de sécurité.
¤ Les beans contiennent la logique métier de l’application, ainsi le développeur du
client peut se concentrer sur la présentation du client. Le développeur client n'a
pas à coder les routines qui accèdent à des bases de données ou implémentent
des règles métier.
¤ Les beans enterprise étant des composants portables, elles peuvent alors être
réutilisés pour créer de nouvelles applications. Sous réserve qu'elles utilisent les
API standard, ces applications peuvent s'exécuter sur tout serveur Java EE
conforme.
Les Beans Enterprise
5

¨ Quand utiliser Enterprise Beans?


¤ L'application doit être évolutive.
¤ Les transactions doivent assurer l'intégrité des données.

¤ L'application aura une variété de clients.

¨ Types de Beans Enterprise :


¤ Session : effectue une tâche pour un client; peut éventuellement
mettre en œuvre un service Web.
¤ Message-driven : agit en tant qu'écouteur pour un type de
messagerie particulier.
Session Bean
6

¨ Un session bean encapsule la logique métier pouvant être


appelée par un programme client via des vues client
locales, distantes ou de Web-services.
¨ Pour accéder à une application déployée sur le serveur, le
client appelle les méthodes du session bean.
¨ Un session bean n'est pas persistant. (Autrement dit, ses
données ne sont pas enregistrées dans une base de
données.)
¨ Les session beans sont de trois types:
¤ stateful,
¤ Stateless
¤ singleton.
Session Bean : Stateful (avec état)
7

¨ Stateful Session Beans :


¤ L'état d'un objet est constitué des valeurs de ses variables d'instance. Dans
un bean de session avec état, les variables d'instance représentent l'état
d'une session client / bean unique.
¤ Étant donné que le client interagit ("dialogue") avec son bean, cet état est
souvent appelé état conversationnel.
¤ Un session bean n'est pas partagé; il ne peut avoir qu'un seul client.
Lorsque le client finit, son bean session semble se terminer et n'est plus
associé au client.
¨ Lorsque le traitement est réalisé en plusieurs étapes: le mode
Stateful
¤ Un Stateful Bean est lié à un client
¤ Les variables d'instance sont conservées entre chaque appel de méthode.
¤ Exemple : un panier d’achat,
¤ Avantage : Parfait pour les flux de travail.
¤ Inconvénient : Impact sur les performances du serveur.
Session Bean : Stateful (avec état)
8

¨ Considérons qu’un serveur d'applications crée un pool d'instances de


Session Bean au démarrage:
¤ À la première fois, deux clients appellent une méthode, chacun obtient son
instance du bean.
¤ À la deuxième fois, ils recommencent et le serveur d'application leur donne
la même instance.
¤ Conclusion: une instance est dédiée à un client.
Session Beans Pool
1 2 3 4 5

getPlaces() getTrips()

Clients
Session Bean : Stateless (sans état)
9

¨ Stateless Session Beans :


¤ Un bean session Stateless ne maintient pas un état de conversation avec le
client.
¤ Lorsqu'un client appelle les méthodes d'un bean sans état, les variables
d'instance du bean peuvent contenir un état spécifique à ce client, mais
uniquement pour la durée de l'appel.
¤ Lorsque la méthode est terminée, l'état spécifique au client ne doit pas
être conservé.
¤ Puisqu'ils peuvent prendre en charge plusieurs clients, les beans session
sans état peuvent offrir une meilleure évolutivité pour les applications
nécessitant un grand nombre de clients.
¤ En règle générale, une application nécessite moins de beans de session
sans état que de beans de session avec état pour prendre en charge le
même nombre de clients.
¤ Un bean session sans état peut implémenter un service Web, mais un bean
session stateful ne peut pas.
Session Bean : Stateless (sans état)
10

¨ Lorsque le traitement est réalisé en une seule étape: le


mode Stateless
¤ Un Stateless Bean n'est lié à aucun client
¤ Exemples : BonjourService, Récupérer une liste de produits

¤ Avantage : Utilise moins de ressources.


Session Bean : Stateless (sans état)
11

¨ Considérons qu’un serveur d'applications crée un pool d'instances de


Session Bean au démarrage:
¤ À la première fois, deux clients appellent une méthode, chacun obtient son
instance du bean.
¤ Dans un deuxième temps, ils recommencent, mais le serveur d'application
pourrait leur donner une instance différente.
¤ Conclusion: une instance n'est pas dédiée à un client.

Session Beans Pool


1 2 3 4 5

getPlaces() getTrips()

Clients
Session Bean : Singleton
12

¨ Singleton Session Beans :


¤ Un bean session singleton est instancié une fois par application et existe pour tout
le cycle de vie de l'application.
¤ Les beans session Singleton sont conçus pour les situations dans lesquelles une seule
instance de bean entreprise est partagée et simultanément accédée par les
clients.
¤ Les beans session Singleton offrent des fonctionnalités similaires aux beans session
sans état, mais ils diffèrent par le fait qu'il n'existe qu'un bean session singleton
par application, par opposition à un pool de beans session sans état, chacun
d'entre eux pouvant répondre à une demande client.
¤ Comme les beans session sans état, les beans session singleton peuvent
implémenter des Web-services.
¤ Les beans session Singleton conservent leur état entre les appels de clients, mais
ne sont pas obligés de le faire après des pannes ou des arrêts de serveur.
¤ Les applications qui utilisent un bean session singleton peuvent spécifier que le
singleton doit être instancié au démarrage de l'application, ce qui permet au
singleton d'effectuer des tâches d'initialisation pour l'application.
¤ Le singleton peut également effectuer des tâches de nettoyage lors de l’arrêt de
l’application, car il fonctionnera tout au long du cycle de vie de l’application.
Quand utiliser les Session Bean?
13
¨ Les beans session Stateful (avec état) sont appropriés si l'une des conditions suivantes est vraie:
¤ L’état du bean représente l’interaction entre le bean et un client spécifique.
¤ Le bean doit contenir des informations sur le client lors d'appels de méthodes.
¤ Le bean sert d'intermédiaire entre le client et les autres composants de l'application et présente une
vue simplifiée au client.
¤ En coulisse, le bean gère le flux de travail de plusieurs beans entreprise.
¨ Pour améliorer les performances, on peut choisir un bean session Stateless (sans état) s'il
possède l'une de ces caractéristiques :
¤ L’état du bean n’a pas de données pour un client spécifique.
¤ Dans un appel de méthode unique, le bean effectue une tâche générique pour tous les clients. Par
exemple, on peut utiliser un bean session sans état pour envoyer un courrier électronique confirmant
une commande en ligne.
¤ Le bean implémente un Web-service.
¨ Les beans session Singleton sont appropriés dans les cas suivants.
¤ L'état doit être partagé dans l'application.
¤ Un seul bean entreprise doit être accessible simultanément par plusieurs threads.
¤ L'application a besoin d'un bean enterprise pour effectuer des tâches au démarrage et à l'arrêt de
l'application.
¤ Le bean implémente un Web-service.
Message-Driven Bean
14

¨ Un Message-Driven bean est un bean entreprise qui permet aux applications


Java EE de traiter les messages de manière asynchrone.
¨ Ce type de bean agit normalement comme un écouteur de messages JMS
(Java Message Service), similaire à un écouteur d'événements mais recevant
des messages JMS au lieu d'événements.
¨ Les messages peuvent être envoyés par tout composant Java EE (un client
d'application, un autre enterprise bean ou un composant Web) ou par une
application ou un système JMS n'utilisant pas la technologie Java EE.
¨ Les beans gérés par message peuvent traiter les messages JMS ou d'autres
types de messages.
¨ La différence la plus visible entre les beans gérés par message et les session
beans est que les clients n'accèdent pas aux Message-Driven beans via des
interfaces.
¨ Contrairement à un session bean, un Message-Driven bean ne comporte
qu'une classe de bean.
Message-Driven Bean
15

¨ Un bean géré par message ressemble à un bean de session sans état.


¤ Les instances d’un bean géré par message ne conservent aucune donnée ni aucun
état de conversation pour un client spécifique.
¤ Toutes les instances d'un bean géré par message sont équivalentes, ce qui permet
au conteneur EJB d'attribuer un message à toute instance de bean géré par
message. Le conteneur peut regrouper ces instances pour permettre le traitement
simultané de flux de messages.
¤ Un seul bean géré par message peut traiter les messages de plusieurs clients.
¨ Les Message-Driven beans ont les caractéristiques suivantes.
¤ Ils s'exécutent à la réception d'un seul message client.
¤ Ils sont appelés de manière asynchrone.
¤ Ils ont une vie relativement courte.
¤ Ils ne représentent pas directement des données partagées dans la base de
données, mais ils peuvent accéder à ces données et les mettre à jour.
¤ Ils peuvent être conscients des transactions.
¤ Ils sont sans état.
Message-Driven Bean
16

¨ Quand utiliser les Message-Driven Beans


¤ Les beans session permettent d'envoyer des messages JMS et
de les recevoir de manière synchrone mais pas asynchrone.
¤ Pour ne pas gêner les ressources du serveur, il ne faut pas
utiliser le blocage des réceptions synchrones dans un
composant côté serveur; En général, les messages JMS ne
doivent pas être envoyés ou reçus de manière synchrone. Pour
recevoir des messages de manière asynchrone, on utilise un
Message-Driven bean.
¤ Les beans gérés par message ne disposent pas d'interfaces ni
de vues sans interface qui définissent l'accès client.
Accéder aux Enterprise Beans
17

¨ Les clients accèdent aux beans entreprise via une interface métier.
¨ Une interface métier est une interface Java standard contenant les méthodes
métier du bean enterprise.
¨ Un client peut accéder à un session
bean uniquement via les méthodes
définies dans l'interface métier du
bean ou via les méthodes publiques
d'un bean d'entreprise ne disposant Interface
d'aucune vue.
Desktop application
¨ L’interface métier définit la vue du
client d’un bean entreprise. Tous les
autres aspects du bean enterprise
(implémentations de méthodes et Interface
paramètres de déploiement) sont
masqués au client. Implementation

¨ Le mode d’accès peut être : Local Session Bean Interface


(par défaut en EJB3.1), Remote, deployed on a server
Web application
WebService.
Accéder aux Enterprise Beans
18

¨ Pour utiliser un bean entreprise, Le client du bean entreprise obtient une


référence à son instance par:
¤ Injection de dépendance, à l'aide d'annotations Java,
¤ Recherche JNDI, à l'aide de la syntaxe Java Naming and Directory Interface
pour rechercher l'instance du bean d'entreprise.
¨ L'injection de dépendance est le moyen implicite le plus simple d'obtenir une
référence de bean enterprise.
¨ Les clients qui s'exécutent dans un environnement géré par un serveur J2EE,
des applications Web JavaServer Faces, des WebServices, d'autres EJB ou
des clients d'application J2EE prennent en charge l'injection de dépendance
à l'aide de l'annotation javax.ejb.EJB (@EJB).
¨ Les applications qui s'exécutent en dehors d'un environnement géré par le
serveur Java EE, telles que les applications Java SE, doivent effectuer une
recherche explicite.
¨ JNDI prend en charge une syntaxe globale d'identification des composants
Java EE afin de simplifier cette recherche explicite.
Accéder aux Enterprise Beans:
Syntaxe JNDI
19
¨ Trois espaces de nom JNDI sont utilisés pour les recherches JNDI portables: java:global, java:module et
java:app.
¨ L'espace de noms JNDI java:global est le moyen portable de rechercher des beans entreprise distants à
l'aide de recherches JNDI. Les adresses JNDI ont la forme suivante:
¤ java:global[/application name]/module name /enterprise bean name[/interface name ]
n Le nom de l'application et le nom du module correspondent par défaut au nom de l'application et du module moins
l'extension de fichier.
n Les noms d'applications ne sont requis que si l'application est intégrée à un fichier EAR.
n Le nom d'interface est requis uniquement si le bean enterprise implémente plusieurs interfaces métier.
¨ L'espace de noms java:module est utilisé pour rechercher des beans enterprise locaux dans le même
module. Les adresses JNDI utilisant l’espace de nom java:module se présentent sous la forme suivante:
¤ java:module/enterprise bean name/[interface name]
n Le nom d'interface est requis uniquement si le bean enterprise implémente plusieurs interfaces métier.
¨ L'espace de noms java:app est utilisé pour rechercher des beans enterprise locaux emballés dans la même
application. En d'autres termes, le bean enterprise est intégré à un fichier EAR contenant plusieurs modules
Java EE. Les adresses JNDI utilisant l’espace de nom java:app sont de la forme suivante:
¤ java:app[/module name]/enterprise bean name [/interface name]
n Le nom du module est optionnel.
n Le nom d'interface est requis uniquement si le bean enterprise implémente plusieurs interfaces métier.
¨ Par exemple, si un bean entreprise, MyBean, est inclus dans l'archive d'application Web myApp.war, le
nom du module est myApp.
¤ Le nom JNDI portable est java:module/MyBean.
¤ Un nom JNDI équivalent utilisant l'espace de noms java:global est java:global/myApp/MyBean.
Accéder aux Enterprise Beans :
Accès distant ou local
20
¨ Lors de la conception d’une application Java EE, l'une des premières décisions à prendre est le type
d'accès client autorisé par les beans enterprise: distant, local ou Web-service.
¨ L'autorisation d'un accès local ou distant dépend des facteurs suivants :
¤ Couplage serré de bean apparentés: Les bean serrés dépendent les uns des autres. Par exemple, si un bean de
session qui traite des commandes appelle un bean de session qui envoie un message de confirmation au client,
ces beans sont étroitement couplés. Les bean étroitement couplés sont de bons candidats pour l'accès local.
Comme ils forment une unité logique, ils s’appellent souvent les uns les autres et tirent parti des performances
accrues possibles grâce à l’accès local.
¤ Type de client: si un client d'application accède à un bean entreprise, il doit autoriser l'accès à distance. Dans
un environnement de production, ces clients s'exécutent presque toujours sur des machines autres que celles sur
lesquelles le serveur d’application est exécuté. Si les clients d’un bean enterprise sont des composants Web ou
d’autres beans, le type d’accès dépend de la manière dont on souhaite répartir nos composants.
¤ Distribution de composants: les applications Java EE sont évolutives car leurs composants côté serveur peuvent
être répartis sur plusieurs ordinateurs. Dans une application distribuée, par exemple, le serveur sur lequel les
composants Web s'exécutent peut ne pas être celui sur lequel les beans d'entreprise auxquels ils ont accès
sont déployés. Dans ce scénario distribué, les beans enterprise doivent autoriser l'accès à distance.
¤ Performances: en raison de facteurs tels que la latence du réseau, les appels distants peuvent être plus lents
que les appels locaux. D'autre part, si on distribue des composants sur différents serveurs, on peut améliorer
les performances globales de l'application. Ces deux déclarations sont des généralisations; les performances
peuvent varier dans différents environnements opérationnels. Néanmoins, on doit garder à l'esprit les effets
de la conception de l’application sur les performances.
¨ Si on ne sait pas quel type d’accès on devrait utiliser, on choisit l’accès distant. Cette décision donne
plus de flexibilité.
Accéder aux Enterprise Beans :
Accès distant ou local
21

¨ Bien que cela soit rare, il est possible qu'un bean


enterprise autorise un accès à la fois distant et local.
¨ Si tel est le cas, l'interface métier du bean doit être
explicitement désignée comme une interface métier en
étant décorée avec les annotations @Remote ou @Local,
ou la classe de bean doit désigner explicitement les
interfaces métier à l'aide des annotations @Remote et
@Local.
¨ La même interface métier ne peut pas être une interface
métier locale ou distante.
Accéder aux Enterprise Beans :
Client Local
22

¨ Un client local a ces caractéristiques:


¤ Il doit être exécuté dans la même application que le bean enterprise
auquel il a accès.
¤ Il peut s'agir d'un composant Web ou d'un autre bean enterprise.
¨ Les méthodes publiques de la classe d'implémentation de bean
entreprise sont exposées aux clients locaux qui accèdent à la vue
sans interface du bean d'entreprise.
¨ Les beans entreprise qui utilisent la vue sans interface
n'implémentent pas d'interface métier.
¨ L’interface métier locale définit les méthodes métier et le cycle de
vie du bean.
¨ Si l'interface métier du bean n'est pas décorée avec @Local ou
@Remote et si la classe de bean ne spécifie pas l'interface à l'aide
de @Local ou @Remote, l'interface métier est par défaut une
interface locale.
Accéder aux Enterprise Beans :
Client Local
23

¨ Pour créer un bean enterprise qui autorise uniquement


l'accès local, on peut, sans y être obligé, effectuer l'une
des opérations suivantes :
¤ Créer une classe d'implémentation de bean entreprise qui
n'implémente pas d'interface métier, indiquant que le bean
expose une vue sans interface aux clients. Par exemple:
@Session
public class MyBean { ... }

¤ Annoter l'interface métier du bean enterprise en tant


qu'interface @Local. Par exemple:
@Local
public interface InterfaceName { ... }
¤ Spécifier l'interface en décorant la classe de bean avec
@Local et spécifier le nom de l'interface. Par exemple:
@Local(InterfaceName.class)
public class BeanName implements InterfaceName { ... }
Accéder aux Enterprise Beans :
Client Local
24

¨ Accès aux beans entreprise locaux à l'aide de la vue sans


interface :
¤ L'accès client à un bean entreprise qui expose une vue locale sans
interface est réalisé par injection de dépendance ou recherche
JNDI.
¤ Pour obtenir une référence à la vue sans interface d’un bean
entreprise par le biais de l’injection de dépendances, on utilise
l’annotation javax.ejb.EJB et on spécifie la classe du bean:
@EJB
ExampleBean exampleBean;
¤ Pour obtenir une référence à la vue sans interface d’un bean
entreprise par le biais de la recherche JNDI, on utilise la méthode
de recherche de l’interface javax.naming.InitialContext:
ExampleBean exampleBean = (ExampleBean)InitialContext.lookup("java:module/ExampleBean");

¤ Les clients n'utilisent pas l'opérateur new pour obtenir une nouvelle
instance d'un bean enterprise utilisant une vue sans interface.
Accéder aux Enterprise Beans :
Client Local
25

¨ Accès aux beans entreprise locaux qui implémentent des


interfaces métier
¤ L'accès client aux beans d'entreprise qui implémentent des
interfaces métier locales est réalisé par injection de dépendance ou
recherche JNDI.
¤ Pour obtenir une référence à l'interface métier locale d'un bean
d'entreprise via l'injection de dépendance, on utilise l'annotation
javax.ejb.EJB et on spécifie le nom de l'interface métier locale du
bean d'entreprise:
@EJB
Example example;

¤ Pour obtenir une référence à une interface métier locale d'un bean
d'entreprise via la recherche JNDI, on utilise la méthode de
recherche de l'interface javax.naming.InitialContext:
ExampleLocal example = (ExampleLocal) InitialContext.lookup("java:module/ExampleLocal");
Accéder aux Enterprise Beans :
Client distant
26

¨ Un client distant (Remote) d'un bean enterprise présente


les caractéristiques suivantes:
¤ Il peut être exécuté sur une autre machine et sur une JVM
différente du bean enterprise auquel il a accès. (Il n'est pas
nécessaire de s'exécuter sur une autre machine virtuelle.)
¤ Il peut s'agir d'un composant Web, d'un client d'application ou
d'un autre bean enterprise.
¤ Le bean enterprise doit implémenter une interface métier. En
d'autres termes, les clients distants ne peuvent pas accéder à
un bean d'entreprise via une vue sans interface.
Accéder aux Enterprise Beans :
Client distant
27

¨ Pour créer un bean enterprise permettant l’accès à distance, on doit soit:


¤ Décorer l'interface métier du bean enterprise avec l'annotation @Remote:
@Remote
public interface InterfaceName { ... }

¤ Ou décorer la classe de bean avec @Remote, en spécifiant l'interface ou les


interfaces métier:
@Remote(InterfaceName.class)
public class BeanName implements InterfaceName { ... }

¨ L'interface distante définit les méthodes métier et les méthodes de cycle de


vie spécifiques au bean.
¨ Par exemple, l'interface distante d'un bean appelé BankAccountBean peut
avoir des méthodes métiers appelées deposit() et credit().
Accéder aux Enterprise Beans :
Client distant
28

¨ L'accès client à un bean entreprise qui implémente une


interface métier distante est obtenu par injection de
dépendance ou recherche JNDI.
¤ Pour obtenir une référence à l'interface métier distante d'un
bean d'entreprise via l'injection de dépendance, on utilise
l'annotation javax.ejb.EJB et on spécifie le nom de l'interface
métier distante du bean d'entreprise:
@EJB
Example example;

¤ Pour obtenir une référence à une interface métier distante d’un


bean entreprise via la recherche JNDI, on utilise la méthode de
recherche de l’interface javax.naming.InitialContext:
ExampleRemote example = (ExampleRemote)
InitialContext.lookup("java:global/myApp/ExampleRemote");
Accéder aux Enterprise Beans :
Client Web-services
29

¨ Un client Webservice peut accéder à une application Java EE de deux manières.


¤ Tout d'abord, le client peut accéder à un Webservice créé avec JAX-WS.
¤ Deuxièmement, un client de service Web peut invoquer les méthodes métier d'un bean de session sans
état. Les beans de message ne sont pas accessibles aux clients du service Web.
¨ À condition qu'il utilise les protocoles appropriés (SOAP, HTTP, WSDL), tout client de service
Web peut accéder à un bean de session sans état, que ce soit écrit ou non en Java.
¨ Le client ne sait même pas quelle technologie implémente le service: bean session sans état,
JAX-WS ou une autre technologie.
¨ De plus, les beans enterprise et les composants Web peuvent être des clients de services Web.
¨ Un client de service Web accède à un bean de session sans état par le biais de la classe
d'implémentation final de service Web.
¨ Par défaut, toutes les méthodes publiques de la classe de bean sont accessibles aux clients du
service Web.
¨ L'annotation @WebMethod peut être utilisée pour personnaliser le comportement des
méthodes de service Web.
¨ Si l'annotation @WebMethod est utilisée pour annoter les méthodes de la classe du bean,
seules les méthodes décorées avec @WebMethod sont exposées aux clients de services Web.
Paramètres de méthode et accès
30
¨ Le type d'accès affecte les paramètres des méthodes de bean appelées par les clients.
¨ Les sections suivantes s'appliquent non seulement aux paramètres de méthode, mais également
aux valeurs de retour de méthode.
¨ Isolement
¤ Les paramètres des appels à distance sont plus isolés que ceux des appels locaux.
¤ Avec les appels à distance, le client et le bean opèrent sur différentes copies d'un objet paramètre. Si
le client modifie la valeur de l'objet, la valeur de la copie dans le bean ne change pas. Cette couche
d'isolation peut aider à protéger le bean si le client modifie accidentellement les données.
¤ Dans un appel local, le client et le bean peuvent modifier le même objet de paramètre. En général, on
ne doit pas compter sur cet effet secondaire des appels locaux. Peut-être qu'un jour on voudra
distribuer les composants, en remplaçant les appels locaux par des appels distants.
¤ Comme avec les clients distants, les clients de service Web utilisent des copies de paramètres
différentes de celles du bean implémentant le service Web.
¨ Granularité des données consultées
¤ Les appels distants étant susceptibles d'être plus lents que les appels locaux, les paramètres des
méthodes distantes doivent être relativement grossiers.
¤ Un objet à grain grossier contient plus de données qu'un objet à grain fin, de sorte que moins d'appels
d'accès sont requis.
¤ Pour la même raison, les paramètres des méthodes appelées par les clients de services Web doivent
également être à grain grossier.
Le contenu d'un bean entreprise
31

¨ Pour développer un bean enterprise, on doit fournir les fichiers


suivants:
¤ Classe de bean entreprise: Implémente les méthodes métier du
bean entreprise et toutes les méthodes de rappel du cycle de vie.
¤ Interfaces métier: définit les méthodes métier implémentées par la
classe de beans enterprise. Une interface métier n'est pas requise si
le bean enterprise expose une vue locale sans interface.
¤ Classes auxiliaires (helper) : autres classes nécessaires à la classe
de bean entreprise, telles que les classes d'exception et les
utilitaires.
¨ On regroupe les objets de la liste précédente dans un fichier
EJB JAR (un module autonome stockant le bean enterprise) ou
dans un module WAR (Web Application Archive).
Packaging des bean entreprise :
EJB JAR Modules
32

¨ Empaquetage de l’Enterprise Beans dans des modules EJB


JAR:
¤ Un fichier EJB JAR est portable et peut être utilisé pour
diverses applications.
¤ La figure montre la structure du JAR EJB
Packaging des bean entreprise :
WAR Modules
33

¨ Empaquetage de Enterprise Beans dans des modules WAR:


¤ Les beans entreprise fournissent souvent la logique métier d'une
application Web. Dans ces cas, l'empaquetage du bean entreprise dans le
module WAR de l'application Web simplifie le déploiement et
l'organisation de l'application.
¤ Les beans entreprise peuvent être empaquetés dans un module WAR sous
forme de fichiers de classe Java ou dans un fichier JAR inclus dans le
module WAR.
¤ Pour inclure des fichiers de classe bean entreprise dans un module WAR,
les fichiers de classe doivent se trouver dans le répertoire WEB-INF /
classes.
¤ Pour inclure un fichier JAR contenant des beans entreprise dans un module
WAR, il faut ajouter le JAR au répertoire WEB-INF / lib du module WAR.
¤ Les modules WAR qui contiennent des beans entreprise ne nécessitent pas
de descripteur de déploiement ejb-jar.xml. Si l'application utilise
ejb-jar.xml, elle doit se trouver dans le répertoire WEB-INF du module
WAR.
Conventions de dénomination pour
les Enterprise Beans
34

¨ Les beans Enterprise étant composés de plusieurs parties, il est utile de suivre
une convention de dénomination pour les applications.
Elément Syntaxe Exemple
Enterprise bean name nameBean accountBean
Enterprise bean class NameBean AccountBean
Business interface Name Account
Cycle de vie des beans entreprise
35

¨ Un bean enterprise traverse différentes étapes au cours de son cycle de vie.


¨ Chaque type de bean enterprise (stateful, stateless, singleton, ou message-
driven) a un cycle de vie différent.
¨ Le cycle de vie d'un Stateful Session Bean
¤ Le client initie le cycle de vie en obtenant une référence à un bean de session avec
état.
¤ Le conteneur effectue toute injection de dépendance, puis appelle la méthode
annotée avec @PostConstruct, le cas échéant.
¤ Le bean est maintenant prêt à avoir ses méthodes métier invoquées par le client.
Cycle de vie : Stateful Session Bean
36

¨ Le client initie le cycle de vie en obtenant une référence à un bean


de session avec état.
¨ Le conteneur effectue toute injection de dépendance, puis appelle la
méthode annotée avec @PostConstruct, le cas échéant.
¨ Le bean est maintenant prêt à avoir ses méthodes métier invoquées
par le client.
¨ Lorsqu'il est prêt, le conteneur EJB peut décider de désactiver ou de
passiver le bean en le déplaçant de la mémoire vers la mémoire
secondaire. (En règle générale, le conteneur EJB utilise l’algorithme
du moins récemment utilisé pour sélectionner le bean à passiver.)
¨ Le conteneur EJB appelle la méthode annotée @PrePassivate, le
cas échéant, immédiatement avant de le passiver. Si un client
appelle une méthode métier sur le bean alors qu'il se trouve dans la
phase passive, le conteneur EJB active le bean, appelle la méthode
annotée @PostActivate, le cas échéant, puis le déplace vers la
phase de disponibilité.
Cycle de vie : Stateful Session Bean
37

¨ À la fin du cycle de vie, le client appelle une méthode annotée


@Remove et le conteneur EJB appelle la méthode annotée
@PreDestroy, le cas échéant. L’instance du bean est alors
prête pour la récupération par le garbage collector.
¨ Le code contrôle l'appel d'une seule méthode de cycle de vie:
la méthode annotée @Remove.
Cycle de vie : Stateless Session Bean
38

¨ Etant donné qu'un bean de session sans état n'est jamais passivé, son cycle de
vie n'a que deux étapes:
¤ Inexistant;
¤ Prêt pour l'invocation de méthodes métier.
¨ Le conteneur EJB crée et gère généralement un pool de beans de session
sans état, en commençant le cycle de vie du bean de session.
¨ Le conteneur effectue toute injection de dépendance, puis appelle la
méthode annotée @PostConstruct, si elle existe.
¨ Le bean est maintenant prêt à avoir ses méthodes métier appelées par un
client.
¨ À la fin du cycle de vie, le conteneur EJB appelle la méthode annotée
@PreDestroy, si elle existe. L’instance du bean est alors prête pour la
récupération par le garbage collector.
Cycle de vie: Singleton Session Bean
39

¨ Comme un bean de session sans état, un bean de session singleton


n'est jamais passivé et ne comporte que deux étapes, inexistant et
prêt pour l'invocation de méthodes métier.
¨ Le conteneur EJB lance le cycle de vie du bean session singleton en
créant l'instance singleton.
¨ Cela se produit lors du déploiement de l'application si le singleton
est annoté avec l'annotation @Startup.
¨ Le conteneur effectue toute injection de dépendance, puis appelle la
méthode annotée @PostConstruct, si elle existe.
¨ Le bean session singleton est maintenant prêt à avoir ses méthodes
métier invoquées par le client.
¨ À la fin du cycle de vie, le conteneur EJB appelle la méthode
annotée @PreDestroy, si elle existe.
¨ Le bean session singleton est maintenant prêt pour la récupération
par le garbage collector.
Cycle de vie : Message-Driven Bean
40

¨ Le conteneur EJB crée généralement un pool d'instances de beans gérées par


message. Pour chaque instance, le conteneur EJB effectue ces tâches:
¤ Si le bean géré par message utilise l'injection de dépendance, le conteneur injecte
ces références avant de l'instancier.
¤ Le conteneur appelle la méthode annotée @PostConstruct, le cas échéant.
¨ Comme un bean session sans état, un bean géré par message n'est jamais
passivé et n'a que deux états: inexistant et prêt à recevoir des messages.
¨ À la fin du cycle de vie, le conteneur appelle la méthode annotée
@PreDestroy, le cas échéant. L’instance du bean est alors prête pour la
récupération par le garbage collector.
Exemples d’Entreprise Beans
41

¨ On va voir par la suite les différents exemples de bean


entreprise de session :
¤ ConverterBean : un bean de session sans état (stateless session
bean).
¤ CartBean : un bean de session avec état avec un client à accès
distant (stateful session bean accessed by a remote client).
¤ CounterBean : un bean de session singleton (singleton session
bean).
¤ HelloServiceBean : un bean de session sans état qui
implémente un Web-service (stateless session bean qui
implemente un web-service).
¤ TimerSessionBean : un bean de session sans état qui définit
une minuterie (stateless session bean qui définit un timer).
Exemples d’Entreprise Beans :
stateless
42

¨ On va voir comment développer, déployer et exécuter un


exemple d’application Java EE simple, appelée convertisseur,
qui utilise un EJB pour sa logique métier.
¨ Le convertisseur, qui est un bean de session sans état (stateless
session bean), sert à calculer les conversions de devises entre le
dirham, l’euro et le dollar.
¨ L'application de conversion se compose d'un bean entreprise
stateless, qui effectue les calculs, et d'un client Web.
¨ Voici un aperçu des étapes à suivre:
¤ Créer le bean enterprise: ConverterBean.
¤ Créer le client Web : ConverterServlet.
¤ Déployer sur le serveur puis tester et exécuter le client Web à l'aide
d'un navigateur.
Créer le Bean entreprise
43

¨ Le bean enterprise dans l’exemple est un bean de session sans état appelé
ConverterBean.
¨ Cette classe implémente deux méthodes métier: dhToDollar et dhToEuro.
¨ Étant donné que la classe de bean enterprise n'implémente pas d'interface
métier, le Bean entreprise expose une vue locale sans interface.
¨ Les méthodes publiques de la classe de beans enterprise sont disponibles
pour les clients qui obtiennent une référence à ConverterBean.
¨ Le code source de la classe ConverterBean est le suivant:
import java.math.BigDecimal;
import javax.ejb.*;
@Stateless
public class ConverterBean {
private BigDecimal dollarRate = new BigDecimal("0.11");
private BigDecimal euroRate = new BigDecimal("0.092");

public BigDecimal dhToDollar(BigDecimal dhs) {


BigDecimal result = dhs.multiply(dollarRate);
return result.setScale(2, BigDecimal.ROUND_UP);
}
public BigDecimal dhToEuro(BigDecimal dhs) {
BigDecimal result = dhs.multiply(euroRate);
return result.setScale(2, BigDecimal.ROUND_UP);
}
}
Créer le client Web du bean
entreprise
44

¨ Le client web du bean entreprise convertisseur n’est qu’une simple servlet


Java appelée ConverterServlet qui est un composant Web qui répond aux
requêtes HTTP.
¨ Cette classe utilise l'injection de dépendance pour obtenir une référence au
bean entreprise ConverterBean.
¨ L'annotation javax.ejb.EJB est ajoutée à la déclaration de variable privé
converter, qui est de type ConverterBean.
¨ ConverterBean expose une vue locale sans interface. La classe
d'implémentation de bean enterprise est donc du type variable.
¨ Lorsque l'utilisateur entre un montant à convertir en dollars et en euros, le
montant est extrait des paramètres de la requête. ensuite, les méthodes
ConverterBean.dhToDollar et ConverterBean.dhToEuro sont appelées pour
afficher les résultats à l'utilisateur.
@WebServlet(urlPatterns = "/")
public class ConverterServlet extends HttpServlet {

@EJB
ConverterBean converter;
…..
Créer le client Web du bean
entreprise
45
import exemplejavaee.converter.ejb.ConverterBean;
import java.io.*;
import java.math.BigDecimal;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet(urlPatterns = "/")
public class ConverterServlet extends HttpServlet {
private static final long serialVersionUID = 7L;
@EJB
ConverterBean converter;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// Output the results
out.println("<html lang=\"en\">");
out.println("<head>");
out.println("<title>Servlet ConverterServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet ConverterServlet at " + request.getContextPath() + "</h1>");
try {
String amount = request.getParameter("amount");
if (amount != null && amount.length() > 0) {
// convert the amount to a BigDecimal from the request parameter
BigDecimal d = new BigDecimal(amount);
// call the ConverterBean.dhToDollar() method to get the amount in Dollar
BigDecimal dollarAmount = converter.dollarToDh(d);
// call the ConverterBean.dhToEuro() method to get the amount in Euro
BigDecimal euroAmount = converter.dhToEuro(d);
out.println("<p>" + amount + " dirhams are " + dollarAmount.toPlainString() + " Dollars.</p>");
out.println("<p>" + amount + " dirhams are " + euroAmount.toPlainString() + " Euro.</p>");
Créer le client Web du bean
entreprise
46
} else {
out.println("<p>Enter a dirham amount to convert:</p>");
out.println("<form method=\"get\">");
out.println("<p><input title=\"Amount\" type=\"text\" name=\"amount\" size=\"25\">Dhs</p>");
out.println("<br/>");
out.println("<input type=\"submit\" value=\"Submit\">" + "<input type=\"reset\"
value=\"Reset\">");
out.println("</form>");
}
} finally {
out.println("</body>");
out.println("</html>");
out.close();
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
Bean de session avec état
47

¨ L'exemple de panier représente une librairie en ligne et utilise un


bean de session avec état pour gérer les opérations du panier.
¨ Le client du bean peut ajouter un livre au panier, supprimer un livre
ou récupérer le contenu du panier.
¨ Pour assembler le panier, on a besoin de :
¤ Classe de bean session (CartBean)
¤ Interface métier distante (Cart)
¨ Tous les beans entreprise qui permettent un accès distant doivent
avoir une interface métier distante.
¨ Pour répondre aux besoins d'une application spécifique, un bean
enterprise peut également avoir besoin de certaines classes
auxiliaires (helper classes).
¨ Le bean session CartBean utilise deux classes auxiliaires,
BookException et IdVerifier.
Bean de session avec état
48

¨ L'interface métier Cart est une interface Java simple qui définit toutes les
méthodes métiers implémentées dans la classe de bean.
¨ Si la classe de bean implémente une interface unique, cette interface est
supposée être l'interface métier.
¨ L'interface métier est une interface locale sauf si elle est annotée avec
l'annotation javax.ejb.Remote; l'annotation javax.ejb.Local est facultative
dans ce cas.
¨ La classe de bean peut implémenter plusieurs interfaces.
¨ Dans ce cas, les interfaces métier doivent être explicitement annotées @Local
ou @Remote ou spécifiées en décorant la classe de bean avec @Local ou
@Remote.
¨ Cependant, les interfaces suivantes sont exclues pour déterminer si la classe
de bean implémente plusieurs interfaces (on ne doit pas les compter):
¤ java.io.Serializable
¤ java.io.Externalizable
¤ N'importe laquelle des interfaces définies par le package javax.ejb
Bean de session avec état
49

¨ Le code source de l'interface métier Cart est le suivant:


import java.util.List;
import javax.ejb.Remote;
import exemplejavaee.cart.utils.BookException;

@Remote
public interface Cart {
public void initialize(String person) throws BookException;

public void initialize(String person, String id) throws BookException;

public void addBook(String title);

public void removeBook(String title) throws BookException;

public List<String> getContents();

public void remove();


}
Bean de session avec état
50

¨ Dans cet exemple, Le bean de session avec état CartBean est une
classe Java simple qui implémente toutes les méthodes métiers de
l'interface métier Cart .
¨ Comme tout bean de session avec état, la classe CartBean doit
répondre aux exigences suivantes.
¤ La classe est annotée @Stateful.
¤ La classe implémente les méthodes métier définies dans l'interface métier.
¨ Les beans de session avec état peuvent également effectuer les
opérations suivantes:
¤ Implémenter l'interface métier du bean.
¤ Implémenter toutes les méthodes facultatives de cycle de vie, annotées
@PostConstruct, @PreDestroy, @PostActivate et @PrePassivate.
¤ Implémenter toutes les méthodes métier facultatives annotées @Remove.
Bean de session avec état
51

¨ Le code source du bean de session avec état CartBean est le suivant:


import java.util.ArrayList;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import exemplejavaee.cart.utils.BookException;
import exemplejavaee.cart.utils.IdVerifier;
@Stateful
public class CartBean implements Cart {
String customerId;
String customerName;
List<String> contents;
@Override
public void initialize(String person) throws BookException {
if (person == null) {
throw new BookException("Null person not allowed.");
} else {
customerName = person;
}
customerId = "0";
contents = new ArrayList<>();
}
Bean de session avec état
52
@Override
public void initialize(String person, String id) throws BookException {
if (person == null) throw new BookException("Null person not allowed.");
else customerName = person;
IdVerifier idChecker = new IdVerifier();
if (idChecker.validate(id)) customerId = id;
else throw new BookException("Invalid id: " + id);
contents = new ArrayList<>();
}
@Override
public void addBook(String title) {
contents.add(title);
}
@Override
public void removeBook(String title) throws BookException {
boolean result = contents.remove(title);
if (result == false)
throw new BookException("\"" + title + "\" not in cart.");
}
@Override
public List<String> getContents() {
return contents;
}
@Remove()
@Override
public void remove() {
contents = null;
}
}
Bean de session avec état
53
import java.util.*;
import exemplejavaee.cart.ejb.Cart;
import exemplejavaee.cart.utils.BookException;
import javax.naming.*;
public class CartClient {
public static void main(String[] args) {
try {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.enterprise.naming.SerialInitContextFactory");
Context context = new InitialContext(props);
Cart cart= (Cart) context.lookup("java:global/CartExempleEJBs/CartBean");
//Cart cart= (Cart) context.lookup("java:global/CartExempleEJBs/CartBean!exemplejavaee.cart.ejb.Cart");
cart.initialize("Duke d'Url", "123"); cart.addBook("Infinite Jest");
cart.addBook("Bel Canto"); cart.addBook("Kafka on the Shore");
List<String> bookList = cart.getContents();
Iterator<String> iterator = bookList.iterator();
while (iterator.hasNext()) {
System.out.println("Retrieving book title from cart: " + iterator.next());
}
System.out.println("Removing \"Gravity's Rainbow\" from cart.");
cart.removeBook("Gravity's Rainbow");
cart.remove();
} catch (BookException ex1) {
System.err.println("Caught a BookException: " + ex1.getMessage());
} catch (NamingException ex2) {
System.err.println("Caught a NamingException: " + ex2.getMessage());
}
}
}
Bean de session avec état
54

//Classe BookException.java
package exemplejavaee.cart.utils;
public class BookException extends Exception {
private static final long serialVersionUID = 6274585742564840905L;
public BookException() {
}
public BookException(String msg) {
super(msg);
}
}

//Classe IdVerifier.java
package exemplejavaee.cart.utils;

public class IdVerifier {


public IdVerifier() {
}
public boolean validate(String id) {
boolean result = true;
for (int i = 0; i < id.length(); i++) {
if (Character.isDigit(id.charAt(i)) == false) {
result = false;
}
}
return result;
}
}
Bean de session avec état
55
Bean de session avec état
56

¨ Méthodes de rappel du cycle de vie


¨ Une méthode de la classe de bean peut être déclarée comme méthode de
rappel de cycle de vie en l'annotant avec les annotations suivantes:
¤ javax.annotation.PostConstruct: les méthodes annotées avec @PostConstruct
sont invoquées par le conteneur sur les instances de bean nouvellement construites
après la fin de l'injection de dépendance et avant l'appel de la première
méthode métier sur le bean d'entreprise.
¤ javax.annotation.PreDestroy: les méthodes annotées avec @PreDestroy sont
appelées une fois la méthode annotée @Remove terminée et avant que le
conteneur ne supprime l'instance de bean enterprise.
¤ javax.ejb.PostActivate: les méthodes annotées avec @PostActivate sont
appelées par le conteneur une fois que celui-ci a déplacé le bean de la mémoire
secondaire vers le statut actif.
¤ javax.ejb.PrePassivate: les méthodes annotées avec @PrePassivate sont
appelées par le conteneur avant qu'il ne passive le bean enterprise, ce qui signifie
qu'il supprime temporairement le bean de l'environnement et l'enregistre dans le
stockage secondaire.
¨ Les méthodes de rappel de cycle de vie doivent retourner void et ne pas
avoir de paramètres.
Bean de session avec état
57

¨ Méthodes métiers
¨ L'objectif principal d'un bean session est d'exécuter des
tâches métier pour le client.
¨ Le client appelle des méthodes métier sur la référence
d'objet obtenue à partir d'une injection de dépendance ou
d'une recherche JNDI.
¨ Du point de vue du client, les méthodes métier semblent
s’exécuter localement, bien qu’elles s’exécutent à distance
dans le bean session.
Bean de session avec état
58

¨ La signature d'une méthode métier doit être conforme à ces règles:


¤ Le nom de la méthode ne doit pas commencer par ejb afin d'éviter les conflits avec les méthodes de
rappel définies par l'architecture EJB. Par exemple, on ne peut pas appeler une méthode métier
ejbCreate ou ejbActivate.
¤ Le modificateur de contrôle d'accès doit être public.
¤ Si le bean autorise l'accès à distance via une interface métier distante, les arguments et les types de
retour doivent être des types légaux pour l'API RMI (Java Remote Method Invocation).
¤ Si le bean est un point de terminaison de service Web JAX-WS, les arguments et les types de retour
pour les méthodes annotées @WebMethod doivent être des types légaux pour JAX-WS.
¤ Si le bean est une ressource JAX-RS, les arguments et les types de retour pour les méthodes de
ressource doivent être des types légaux pour JAX-RS.
¤ Le modificateur ne doit pas être static ou final.
¨ La clause throws peut inclure des exceptions qu’on définit pour l’application. La méthode
removeBook, par exemple, lève une exception BookException si le livre n'est pas dans le
panier.
¨ Pour indiquer un problème au niveau du système, tel que l'impossibilité de se connecter à une
base de données, une méthode métier doit émettre une exception javax.ejb.EJBException.
Bean de session avec état
59

¨ La méthode @Remove
¤ Les méthodes métier annotées avec javax.ejb.Remove dans la classe de
bean de session avec état peuvent être appelées par les clients de bean
enterprise pour supprimer l'instance de bean.
¤ Le conteneur supprimera le bean enterprise après qu'une méthode
@Remove se termine normalement ou anormalement.
¨ Classes auxiliaires (Helper)
¤ Le bean session CartBean a deux classes auxiliaires:
n BookException : L’exception BookException est levée par la méthode removeBook
n IdVerifier : La classe IdVerifier valide le customerId dans l'une des méthodes
de création.
¤ Les classes auxiliaires peuvent résider dans un fichier JAR EJB contenant la
classe de bean entreprise; un fichier WAR si le bean enterprise est intégré à
un WAR; ou un fichier EAR contenant un fichier EJB JAR, un fichier WAR ou un
fichier JAR de bibliothèque séparé.
¤ Dans le panier, les classes auxiliaires sont incluses dans un fichier JAR de
bibliothèque utilisé par le client d'application et le fichier JAR EJB.
Bean de Session Singleton
60

¨ L'exemple de compteur counter montre comment créer un


bean de session singleton.
¨ Les sujets suivants sont abordés ici:
¤ Création d'un bean session singleton :
n Initialisation de Singleton Session Beans
n Gestion de l'accès simultané dans un bean session singleton.
n Concurrence gérée par conteneur.
n Concurrence gérée par le bean
n Gestion des erreurs dans un bean session singleton
¤ L'architecture de l’exemple du compteur
Bean de Session Singleton
61

¨ Création d'un bean session singleton:


¤ L'annotation javax.ejb.Singleton est utilisée pour spécifier que la classe
d'implémentation de bean entreprise est un bean de session singleton:
@Singleton
public class SingletonBean { ... }

¨ Initialisation d'un bean session singleton :


¤ Le conteneur EJB est chargé de déterminer quand initialiser une instance
de bean de session singleton, sauf si la classe d'implémentation de bean
session unique est annotée avec l'annotation javax.ejb.Startup.
¤ Dans ce cas, parfois appelé initialisation rapide, le conteneur EJB doit
initialiser le bean singleton de session au démarrage de l'application.
¤ Le bean session singleton est initialisé avant que le conteneur EJB ne
réponde aux demandes du client à aucun bean enterprise de l'application.
¤ Cela permet au bean session singleton d’exécuter, par exemple, des
tâches de démarrage d’application.
Bean de Session Singleton
62

¨ Initialisation d'un bean session singleton :


¤ Le bean singleton de session suivant stocke le statut d'une application et est initialisé avec
impatience (rapidement):
@Startup
@Singleton
public class StatusBean {
private String status;

@PostConstruct
void init{
status = "Ready";
}
...
}
¤ Parfois, plusieurs beans singleton sont utilisés pour initialiser les données d'une application
et doivent donc être initialisés dans un ordre spécifique.
¤ Dans ces cas, on utilise l'annotation javax.ejb.DependsOn pour déclarer les dépendances
de démarrage du bean de session singleton.
¤ L’attribut value de l’annotation @DependsOn est constitué d’une ou de plusieurs chaînes
spécifiant le nom du bean de session singleton cible.
¤ Si plus d'un bean singleton dépendant est spécifié dans @DependsOn, l'ordre dans lequel
ils sont répertoriés n'est pas nécessairement l'ordre dans lequel le conteneur EJB initialisera
les beans de session singleton cibles.
Bean de Session Singleton
63

¨ Initialisation d'un bean session singleton :


¤ Le bean de session singleton suivant, PrimaryBean, doit être
démarré en premier:
@Singleton
public class PrimaryBean { ... }

¤ SecondaryBean dépend de PrimaryBean:


@Singleton
@DependsOn("PrimaryBean")
public class SecondaryBean { ... }

¤ Cela garantit que le conteneur EJB initialisera PrimaryBean


avant SecondaryBean.
¤ Le bean session singleton suivant, TertiaryBean, dépend de
PrimaryBean et SecondaryBean:
@Singleton
@DependsOn({"PrimaryBean", "SecondaryBean"})
public class TertiaryBean { ... }
Bean de Session Singleton
64

¨ Initialisation d'un bean session singleton :


¤ SecondaryBean exige explicitement que PrimaryBean soit
initialisé avant, par le biais de sa propre annotation
@DependsOn.
¤ Dans ce cas, le conteneur EJB initialisera d'abord PrimaryBean,
puis SecondaryBean et enfin TertiaryBean.
¤ Si, toutefois, SecondaryBean ne dépend pas explicitement de
PrimaryBean, le conteneur EJB peut initialiser soit PrimaryBean,
soit SecondaryBean.
¤ C'est-à-dire que le conteneur EJB peut initialiser les singletons
dans l'ordre suivant: SecondaryBean, PrimaryBean,
TertiaryBean.
Bean de Session Singleton
65

¨ Gestion de l'accès simultané dans un bean de session singleton


¤ Les beans de session Singleton sont conçus pour un accès simultané, dans lequel de
nombreux clients doivent accéder à une instance unique d'un bean session en
même temps.
¤ Un client de bean singleton n'a besoin que d'une référence à un singleton pour
pouvoir invoquer les méthodes métier exposées par le singleton et n'a pas besoin
de s'inquiéter des autres clients pouvant appeler simultanément des méthodes
métier sur le même singleton.
¤ Lors de la création d’un bean de session singleton, l’accès simultané aux méthodes
métier de singleton peut être contrôlé de deux manières: accès simultanés gérés
par le conteneur et accès concurrentiels gérés par le bean.
¤ L'annotation javax.ejb.ConcurrencyManagement est utilisée pour spécifier la
simultanéité gérée par le conteneur ou gérée par le bean singleton.
¤ Avec @ConcurrencyManagement, un attribut de type doit être défini sur
javax.ejb.ConcurrencyManagementType.CONTAINER ou sur
javax.ejb.ConcurrencyManagementType.BEAN.
¤ Si aucune annotation @ConcurrencyManagement n'est présente sur la classe
d'implémentation singleton, la valeur par défaut du conteneur EJB de la
simultanéité gérée par le conteneur est utilisée.
Bean de Session Singleton
66

¨ Gestion de l'accès simultané dans un bean de session singleton


¤ Concurrence gérée par conteneur
n Si un singleton utilise la concurrence gérée par le conteneur, le conteneur EJB contrôle
l'accès client aux méthodes métier du singleton.
n L’annotation javax.ejb.Lock et un type javax.ejb.LockType permettent de spécifier le
niveau d’accès des méthodes métier du singleton ou des méthodes @Timeout.
n Les types énumérés LockType sont READ et WRITE:
n Annoter une méthode d’exécution ou méthode délai d'attente d’un singleton avec @Lock
(LockType.READ) si la méthode peut être utilisée simultanément, ou partagée, avec plusieurs
clients.
n Annoter la méthode métier ou le délai d’expiration avec @Lock (LockType.WRITE) si le bean
singleton de session doit être verrouillé sur d’autres clients pendant qu’un client appelle cette
méthode.
n En règle générale, l'annotation @Lock (LockType.WRITE) est utilisée lorsque les clients
modifient l'état du singleton. L'annotation d'une classe singleton avec @Lock spécifie que
toutes les méthodes métier et toutes les méthodes de délai d'expiration du singleton
utiliseront le type de verrou spécifié, sauf si elles définissent explicitement le type de
verrouillage avec une annotation @Lock au niveau de la méthode.
n Si aucune annotation @Lock n'est présente sur la classe singleton, le type de verrou par
défaut, @Lock (LockType.WRITE) , est appliqué à toutes les méthodes métier et de
délai d'expiration.
Bean de Session Singleton
67

¨ Gestion de l'accès simultané dans un bean de session singleton


¤ Concurrence gérée par conteneur
n L'exemple suivant montre comment utiliser les annotations @ConcurrencyManagement, @Lock
(LockType.READ) et @Lock (LockType.WRITE) pour un singleton utilisant la Concurrence gérée par
le conteneur.
n Bien que, par défaut, les singletons utilisent la Concurrence gérée par le conteneur, l'annotation
@ConcurrencyManagement (CONTAINER) peut être ajoutée au niveau de la classe du singleton
pour définir explicitement le type de gestion de la Concurrence :
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@Singleton
public class ExampleSingletonBean {
private String state;
@Lock(LockType.READ)
public String getState() { return state;
}
@Lock(LockType.WRITE)
public void setState(String newState) { state = newState;
}
}
n De nombreux clients peuvent accéder à la méthode getState simultanément car elle est annotée
avec @Lock (LockType.READ) .
n Cependant, lorsque la méthode setState est appelée, toutes les méthodes de
ExampleSingletonBean sont verrouillées sur d'autres clients car setState est annoté avec @Lock
(LockType.WRITE).
n Cela empêche deux clients d'essayer de modifier simultanément la variable d'état de
ExampleSingletonBean.
Bean de Session Singleton
68

¨ Gestion de l'accès simultané dans un bean de session singleton


¤ Concurrence gérée par conteneur
n Les méthodes getData et getStatus du singleton suivant sont de type READ
et la méthode setStatus est de type WRITE :
@Singleton
@Lock(LockType.READ)
public class SharedSingletonBean {
private String data;
private String status;
public String getData() {
return data;
}
public String getStatus() {
return status;
}
@Lock(LockType.WRITE)
public void setStatus(String newStatus) {
status = newStatus;
}
}

n Si une méthode est du type de verrouillage WRITE, l’accès client à toutes


les méthodes du singleton est bloqué jusqu’à ce que le client actuel ait
terminé son appel de méthode ou jusqu’à ce qu’un délai d'attente d’accès
se produit.
n Lorsqu'un délai d'attente d'accès survient, le conteneur EJB lève une
exception javax.ejb.ConcurrentAccessTimeoutException.
Bean de Session Singleton
69

¨ Gestion de l'accès simultané dans un bean de session singleton


¤ Concurrence gérée par conteneur
n L'annotation javax.ejb.AccessTimeout permet de spécifier le nombre de
millisecondes précédant l'expiration du délai d'accès.
n Si ajouté au niveau de la classe d'un singleton, @AccessTimeout spécifie la
valeur de délai d'attente d'accès pour toutes les méthodes du singleton à moins
qu'une méthode ne remplace explicitement la valeur par défaut par sa propre
annotation @AccessTimeout.
n L'annotation @AccessTimeout peut être appliquée aux méthodes @Lock
(LockType.READ) et @Lock (LockType.WRITE).
n L'annotation @AccessTimeout comporte un élément obligatoire, une valeur et
un élément facultatif, l'unité. Par défaut, la valeur est spécifiée en millisecondes.
n Pour modifier l'unité de valeur, définissez l'unité sur l'une des constantes
java.util.concurrent.TimeUnit: NANOSECONDS, MICROSECONDS,
MILLISECONDS ou SECONDS.
n Le singleton suivant a une valeur de délai d'attente d'accès par défaut de 60
secondes, spécifiée à l'aide de la constante TimeUnit.SECONDS:
@Singleton
@AccessTimeout(value=60, unit=TimeUnit.SECONDS)
public class StatusSingletonBean { ... }
Bean de Session Singleton
70

¨ Gestion de l'accès simultané dans un bean de session singleton


¤ Concurrence gérée par le bean
n Les singletons utilisant la concurrence d'accès gérée par un bean permettent un
accès simultané complet à toutes les méthodes métier et de délai d'attente dans
le singleton.
n Le développeur du singleton est responsable de la synchronisation de son état
entre tous les clients.
n Les développeurs qui créent des singletons avec une concurrence gérée par un
bean sont autorisés à utiliser les primitives de synchronisation du langage de
programmation Java, telles que la synchronisation et volatile, pour éviter les
erreurs lors de l'accès simultané.
n Ajouter une annotation @ConcurrencyManagement avec le type défini sur
ConcurrencyManagementType.BEAN au niveau de la classe du singleton pour
spécifier la simultanéité gérée par le bean:

@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@Singleton
public class AnotherSingletonBean { ... }
Bean de Session Singleton
71

¨ Gestion des erreurs dans un bean session singleton


¤ Si un bean session singleton rencontre une erreur lors de
l'initialisation par le conteneur EJB, cette instance singleton est
détruite.
¤ Contrairement aux autres beans entreprise, une fois qu'une
instance de bean session singleton est initialisée, elle n'est pas
détruite si les méthodes métier ou le cycle de vie de singleton
génèrent des exceptions système.
¤ Cela garantit que la même instance singleton est utilisée tout
au long du cycle de vie de l'application.
Bean de Session Singleton
72

¨ L'architecture de l’Exemple du compteur


¤ L'exemple de compteur consiste en un bean de session singleton,
CounterBean et un client Web front-end JavaServer Faces (Facelets).
¤ CounterBean est un simple singleton avec une méthode, getHits, qui renvoie
un entier représentant le nombre d'accès à une page Web.
¤ L'annotation @Singleton marque CounterBean en tant que bean de session
singleton.
¤ CounterBean utilise une vue locale sans interface.
¤ CounterBean utilise les valeurs de métadonnées par défaut du conteneur
EJB pour les singletons afin de simplifier le codage de la classe
d’implémentation singleton.
¤ Il n'y a pas d'annotation @ConcurrencyManagement sur la classe. Par
conséquent, par défaut, l'accès simultané est géré par le conteneur.
¤ Il n'y a pas d'annotation @Lock sur la classe ou la méthode métier. Par
conséquent, la valeur par défaut de @Lock (WRITE) est appliquée à la
seule méthode métier, getHits.
Bean de Session Singleton
73

¨ L'architecture de l’Exemple du compteur


¤ L'annotation @Singleton marque CounterBean en tant que bean de
session singleton. CounterBean utilise une vue locale sans interface.
¤ CounterBean utilise les valeurs de métadonnées par défaut du
conteneur EJB pour les singletons afin de simplifier le codage de la
classe d’implémentation singleton. Il n'y a pas d'annotation
@ConcurrencyManagement sur la classe. Par conséquent, par
défaut, l'accès simultané est géré par le conteneur. Il n'y a pas
d'annotation @Lock sur la classe ou la méthode métier. Par
conséquent, la valeur par défaut de @Lock (WRITE) est appliquée
à la seule méthode métier, getHits.
¤ Les deux versions suivantes de CounterBean sont fonctionnellement
équivalentes :
Bean de Session Singleton
74
package exemplejavaee.counter.ejb;
import javax.ejb.Singleton;
import javax.ejb.Stateful;
import javax.ejb.Stateless;
@Singleton
public class CounterBean {
private int hits = 1;
// Increment and return the number of hits
public int getHits() {
return hits++;
}
}
package exemplejavaee.counter.ejb;
import javax.ejb.Singleton;
import javax.ejb.ConcurrencyManagement;
import static javax.ejb.ConcurrencyManagementType.CONTAINER;
import javax.ejb.Lock;
import javax.ejb.LockType.WRITE;
@Singleton
@ConcurrencyManagement(CONTAINER)
public class CounterBean {
private int hits = 1;
// Increment and return the number of hits
@Lock(WRITE)
public int getHits() {
return hits++;
}
}
Bean de Session Singleton
75

¨ L'architecture de l’Exemple du compteur


¤ Count.java est le client Web frontal du compteur qui consiste en
un bean géré (JavaServer Faces Managed bean), utilisé par le
fichier Facelets XHTML index.xhtml.
¤ Le bean géré Count obtient une référence à CounterBean via
une injection de dépendance.
¤ Count définit une propriété JavaBeans hitCount.

¤ Lorsque la méthode getHitCount est appelée à partir des


fichiers XHTML, la méthode getHits de CounterBean est
appelée pour renvoyer le nombre actuel de visites de la page.
Bean de Session Singleton
76

package exemplejavaee.counter.web;

import java.io.Serializable;
import javax.ejb.EJB;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;
import exemplejavaee.counter.ejb.CounterBean;

@Named
@ConversationScoped
public class Count implements Serializable {
@EJB
private CounterBean counterBean;
private int hitCount;

public Count() {
this.hitCount = 0;
}

public int getHitCount() {


hitCount = counterBean.getHits();
return hitCount;
}

public void setHitCount(int newHits) {


this.hitCount = newHits;
}
}
Bean de Session Singleton
77

¨ L'architecture de l’Exemple du compteur


¤ Le fichier index.xhtml permet de restituer une vue Facelets qui
affiche le nombre de hits (visites) de cette vue.
¤ Le fichier index.xhtml utilise une instruction EL Expression Language,
# {count.hitCount} , pour accéder à la propriété hitCount du bean
géré Count.
<?xml version='1.0' encoding='UTF-8' ?>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<meta http-equiv="Content-Type" content="text/html" />
<title>counter - A singleton session bean example.</title>
<h:outputStylesheet library="css" name="default.css" />
</h:head>
<body>
<h1>Cette page est accédée #{count.hitCount} fois.</h1>
<p>Merci pour votre visite!</p>
</body>
</html>
Web Service
78

¨ Exemple de Web service : helloservice


¤ Cet exemple illustre un service Web simple qui génère une
réponse en fonction des informations reçues du client.
¤ HelloServiceBean est un bean de session sans état qui
implémente une seule méthode: sayHello.
Web Service
79

¨ Classe d'implémentation de point de terminaison du Web service (Web


Service Endpoint Implementation Class )
¤ HelloServiceBean est la classe d'implémentation de point de terminaison,
généralement Enterprise Bean est l'artefact de programmation principal pour les
points de terminaison de Web service.
¤ La classe d'implémentation de noeud final du Web service a les exigences
suivantes :
n La classe doit être annotée avec l'annotation javax.jws.WebService ou
javax.jws.WebServiceProvider.
n La classe d'implémentation peut explicitement référencer une SEI (Service Endpoint
Interface) par le biais de l'élément endpointInterface de l'annotation @WebService,
mais ce n'est pas obligatoire. Si aucun endpointInterface n'est spécifié dans
@WebService, une SEI est définie implicitement pour la classe d'implémentation.
n Les méthodes métier de la classe d'implémentation doivent être publiques et ne doivent
pas être déclarées static ou final.
n Les méthodes métier exposées aux clients de services Web doivent être annotées avec
javax.jws.WebMethod.
n Les méthodes métier exposées aux clients du Web service doivent avoir des paramètres
et des types de retour compatibles avec JAXB.
Web Service
80

¤ La classe d'implémentation de noeud final du Web service a


les exigences suivantes :
n La classe implémentée ne doit pas être déclarée final ni abstract.
n La classe d'implémentation doit avoir un constructeur public par
défaut.
n La classe de point de terminaison doit être annotée @Stateless.
n La classe d'implémentation ne doit pas définir la méthode finalize.
n La classe d'implémentation peut utiliser les annotations
javax.annotation.PostConstruct ou javax.annotation.PreDestroy
sur ses méthodes de rappel des événements de cycle de vie.
n La méthode @PostConstruct est appelée par le conteneur avant que la
classe d'implémentation ne commence à répondre aux clients du Web
service.
n La méthode @PreDestroy est appelée par le conteneur avant que le
noeud final ne soit supprimé de l'opération.
Web Service
81

¨ Exemple de Web service : helloservice


¤ La classe HelloServiceBean implémente la méthode sayHello, annotée
@WebMethod.
¤ Le code source de la classe HelloServiceBean est le suivant:
package exemplejavaee.helloservice.ejb;

import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;
/**
* HelloServiceBean is a web service endpoint implemented as a stateless session bean.
*/
@Stateless
@WebService
public class HelloServiceBean {
private final String message = "Hello, ";

public void HelloServiceBean() {}

@WebMethod
public String sayHello(String name) {
return message + name + ".";
}
}
Web Service
82

¨ Pour tester l’exemple de Web service : helloservice


¤ Déployer le projet dans un serveur d’application (ex:payara,
glassfish, ...)
¤ Ouvrir la console d'administration du serveur via l'URL suivant:
http://localhost:4848/
¤ Sélectionner le nœud Applications et cliquer sur le lien helloservice.
¤ Cliquer sur le lien Afficher le point de terminaison(Endpoint), puis
cliquer sur le lien de Teste:
http://localhost:8080/HelloService/HelloServiceBean?Tester
¤ Sur la page de Teste de service Web, entrer un nom comme
paramètre de la méthode sayHello et Cliquer pour tester.
Web Service
83
Web Service
84
Timer Service
85

¨ Les applications qui modélisent les flux de travail (Workfows) reposent


souvent sur des notifications temporisées.
¨ Le service de minuterie du conteneur d’EJB permet de planifier des
notifications temporisées pour tous les types d’entreprise beans, à l'exception
des beans de session avec état.
¨ On peut planifier une notification chronométrée selon un calendrier, à une
heure précise, après une durée donnée ou à des intervalles de temps définis.
Par exemple, on peut configurer les minuteries pour s’éteindre le 23 mai à 10
h 30, dans les 30 jours ou toutes les 12 heures.
¨ Les Enterprise bean timers (temporisateurs d’Enterprise bean) sont soit des
temporisateurs programmatiques, soit des temporisateurs automatiques :
¤ Les temporisateurs programmatiques sont définis en appelant explicitement l’une
des méthodes de création de temporisateur de l’interface TimerService.
¤ Des temporisateurs automatiques sont créés lors du déploiement réussi d'un
enterprise bean contenant une méthode annotée avec les annotations
javax.ejb.Schedule ou javax.ejb.Schedules.
Timer Service
86

¨ Création d'expressions de minuterie basées sur le


calendrier :
¤ Les minuteries (temporisateurs) peuvent être définies selon un
calendrier.
¤ Les minuteries programmatiques et automatiques peuvent
utiliser des expressions de minuterie basées sur un calendrier.
¤ Le tableau présente les attributs de minuterie basés sur un
calendrier :
Timer Service
Attribut
87 Description Default Plage de Valeurs & Exemples
second One or more seconds within a minute 0 0 to 59. For example: second="30".
minute One or more minutes within an hour 0 0 to 59. For example: minute="15".
hour One or more hours within a day 0 0 to 23. For example: hour="13".
0 to 7 (both 0 and 7 refer to Sunday). For
example: dayOfWeek="3".
dayOfWeek One or more days within a week *
Sun, Mon, Tue, Wed, Thu, Fri, Sat. For
example:dayOfWeek="Mon".
1 to 31. For example: dayOfMonth="15".
–7 to –1 (a negative number means the nth
day or days before the end of the month).
For example: dayOfMonth="–3".
dayOfMonth One or more days within a month *
Last. For example: dayOfMonth="Last".
[1st, 2nd, 3rd, 4th, 5th, Last]
[Sun, Mon, Tue, Wed, Thu, Fri, Sat]. For
example: dayOfMonth="2nd Fri".
1 to 12. For example: month="7".
month One or more months within a year * Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep,
Oct, Nov, Dec. For example: month="July".
year A particular calendar year * A four-digit calendar year : year="2011".
Timer Service
88

¨ Création d'expressions de minuterie basées sur le calendrier : valeurs multiples


¤ Caractères génériques dans les expressions : La définition d'un attribut sur un astérisque (*)
représente toutes les valeurs autorisées pour l'attribut. minute="*"
¤ Liste de valeurs : Pour spécifier deux valeurs ou plus pour un attribut, utiliser une virgule (,)
pour séparer les valeurs. Une plage de valeurs est autorisée dans une liste. Les caractères
génériques et les intervalles ne sont toutefois pas autorisés. Les doublons dans une liste sont
ignorés. hour="4,9-17,22"
¤ Plage de valeurs : Utiliser un tiret (-) pour spécifier une plage de valeurs inclusive pour un
attribut. Les membres d'une plage ne peuvent pas être des caractères génériques, des listes
ou des intervalles. Une plage de la forme x-x est équivalente à l'expression à valeur
unique x. Une plage de la forme x-y où x est supérieur à y équivaut à l'expression x-
`maximumvalue, `minimumvalue`-y`. hour="9-17" ; dayOfMonth="25-5" est equivalent à
dayOfMonth="25-Last,1-5 »
¤ Intervalles de valeurs : La barre oblique (/) limite un attribut à un point de départ et à un
intervalle. Elle permet de spécifier toutes les N secondes, minutes ou heures dans la minute,
l'heure ou le jour. Pour une expression de la forme x / y, x représente le point de départ et
y représente l'intervalle. Le caractère générique peut être utilisé à la position x d'un
intervalle et équivaut à définir x sur 0. Les intervalles ne peuvent être définis que pour les
attributs de seconde, minute et heure. minute="*/10" est équivalent à
minute="0,10,20,30,40,50"
Timer Service
89

¨ Programmatic Timers (Minuteries Programmatiques) :


¤ Lorsqu'un Programmatic Timer expire (s'éteint), le conteneur
appelle la méthode annotée @Timeout dans la classe
d'implémentation du bean. La méthode @Timeout contient la
logique métier qui gère l'événement chronométré.
¤ Les méthodes annotées @Timeout dans la classe de bean
enterprise doivent renvoyer void et éventuellement prendre un
objet javax.ejb.Timer comme seul paramètre. Ils ne peuvent
pas lancer d'exceptions d'application:

@Timeout
public void timeout(Timer timer) {
System.out.println("TimerBean: timeout occurred");
}
Timer Service
90

¨ Programmatic Timers (Minuteries Programmatiques) :


¤ Pour créer une minuterie, le bean appelle l'une des méthodes de création
de l'interface TimerService. Ces méthodes permettent de créer des timers
basés sur une seule action, un intervalle ou un calendrier.
¤ Pour un timer à simple action ou à intervalle, son expiration peut être
exprimée sous forme de durée ou de temps absolu.
nLa durée est exprimée en millisecondes avant qu'un événement de délai
d'attente ne soit déclenché.
n Pour spécifier une heure absolue, créer et transmetter un objet java.util.Date à
la méthode TimerService.createSingleActionTimer ou à la méthode
TimerService.createTimer.
long duration = 60000;
n Exemples : //1 minute (60,000 milliseconds)
Timer timer1 = timerService.createSingleActionTimer(duration, new TimerConfig());

SimpleDateFormatter formatter = new SimpleDateFormatter("MM/dd/yyyy 'at' HH:mm");


Date date = formatter.parse("01/01/2019 at 23:59");
Timer timer2 = timerService.createSingleActionTimer(date, new TimerConfig());

Timer timer3 = timerService.createTimer(intervalDuration, "new programmatic timer");


Timer Service
91

¨ Programmatic Timers (Minuteries Programmatiques) :


¤ Pour un timer basé sur un calendrier, son expiration est
exprimée sous la forme d'un objet
javax.ejb.ScheduleExpression, transmis en tant que
paramètre à la méthode TimerService.createCalendarTimer.
n La classe ScheduleExpression représente des expressions de
minuterie basées sur un calendrier et possède des méthodes
correspondant aux attributs décrits dans le tableau précédent
contenant des expressions de minuterie basées sur un calendrier.
n Exemple :

ScheduleExpression schedule = new ScheduleExpression();


schedule.dayOfWeek("Mon");
schedule.hour("12-17, 23");
Timer timer = timerService.createCalendarTimer(schedule);
Timer Service
92

¨ Programmatic Timers (temporisateur Programmatiques) :


¤ Les timers sont persistants par défaut. Si le serveur est arrêté ou
tombe en panne, les timers persistants sont enregistrés et
redeviendront actifs au redémarrage du serveur. Si un timer
persistant expire alors que le serveur est en panne, le conteneur
appelle la méthode @Timeout lors du redémarrage du serveur.
¤ Des timers programmatiques non persistants sont créés en appelant
TimerConfig.setPersistent (false) et en transmettant l'objet
TimerConfig à l'une des méthodes de création du timer.
¤ Les paramètres Date et long des méthodes createTimer
représentent l'heure avec la résolution en millisecondes. Toutefois,
comme le service timer n'est pas destiné aux applications en temps
réel, il est possible qu'un rappel de la méthode @Timeout ne se
produise pas avec une précision à la milliseconde. Le service de
minuteur est destiné aux applications métier, qui mesurent
généralement le temps en heures, en jours ou sur des durées plus
longues.
Timer Service
93

¨ Automatic Timers (Minuteries ou temporisateur Automatiques) :


¤ Les temporisateurs automatiques sont créés par le conteneur EJB
lorsqu'un bean entreprise, contenant des méthodes annotées avec les
annotations @Schedule ou @Schedules, est déployé.
¤ Un bean entreprise peut avoir plusieurs méthodes de délai
d'expiration automatique, contrairement à un timer programmatique
qui n'autorise qu'une méthode annotée avec l'annotation @Timeout
dans la classe de bean entreprise.
¤ Les timers automatiques peuvent être configurées à l'aide
d'annotations ou du descripteur de déploiement ejb-jar.xml.
¤ L'ajout d'une annotation @Schedule sur un bean enterprise marque
cette méthode comme une méthode de délai d'attente conformément
au calendrier spécifié dans les attributs de l’annotation @Schedule.
Timer Service
94

¨ Automatic Timers (Minuteries ou temporisateurs Automatiques):


¤ L'annotation @Schedule contient des éléments qui correspondent aux expressions
de calendrier détaillées dans le tableau précédent contenant des expressions de
timer basées sur un calendrier et aux éléments persistant, info et fuseau horaire
(persistent, info, and timezone).
¤ L'élément facultatif persistent prend une valeur booléenne et est utilisé pour
spécifier si le minuteur automatique doit survivre au redémarrage ou à une panne
du serveur. Par défaut, tous les temporisateurs automatiques sont persistants.
¤ L'élément facultatif timezone est utilisé pour spécifier que le temporisateur
automatique est associé à un fuseau horaire particulier. S'il est défini, cet élément
évaluera toutes les expressions du minuteur en relation avec le fuseau horaire
spécifié, quel que soit le fuseau horaire dans lequel le conteneur EJB est en cours
d'exécution. Par défaut, tous les minuteries automatiques définies sont en relation
avec le fuseau horaire par défaut du serveur.
¤ L'élément optionnel info est utilisé pour définir une description informative du
temporisateur. Les informations d’une minuterie peuvent être récupérées
ultérieurement à l’aide de Timer.getInfo.
Timer Service
95

¨ Automatic Timers (Minuteries ou temporisateurs Automatiques):


¤ La méthode de temporisation suivante utilise @Schedule pour définir une
minuterie qui expirera tous les dimanches à minuit:
@Schedule(dayOfWeek="Sun", hour="0")
public void cleanupWeekData() { ... }

¤ L'annotation @Schedules est utilisée pour spécifier plusieurs expressions


de minuterie basées sur un calendrier pour une méthode de délai
d'expiration donnée.
n La méthode de délai d'expiration suivante utilise l'annotation @Schedules pour
définir plusieurs expressions de temporisateur basées sur un calendrier. La
première expression définit une minuterie pour qu'elle expire le dernier jour de
chaque mois. La deuxième expression définit une minuterie pour expirer tous les
vendredis à 23h00:

@Schedules ({
@Schedule(dayOfMonth="Last"),
@Schedule(dayOfWeek="Fri", hour="23")
})
public void doPeriodicCleanup() { ... }
Timer Service
96

¨ Annulation des Timers


¤ Les timers peuvent être annulés par les événements suivants :
n Lorsqu’un timer à événement unique expire, le conteneur EJB appelle la méthode de
délai d'attente timeout associée, puis annule le timer.
n Lorsque le bean appelle la méthode cancel de l'interface Timer, le conteneur annule le
timer.
¤ Si une méthode est appelée sur un timer annulé, le conteneur lève l'exception
javax.ejb.NoSuchObjectLocalException.
¨ Enregistrement des Timers
¤ Afin d’enregistrer la référence d’un objet Timer pour usage ultérieur, appeler sa
méthode getHandle et stocker l’objet TimerHandle dans une base de données.
(Un objet TimerHandle est sérialisable.)
¤ Pour rétablir l'objet Timer, extrayer le descripteur (handle) de la base de
données et appeler getTimer sur le descripteur.
n Un objet TimerHandle ne peut pas être transmis en tant qu'argument d'une méthode
définie dans une interface de service Web ou distante. En d’autres termes, les clients
distants et les clients du service Web ne peuvent pas accéder à l’objet TimerHandle
d’un bean.
n Les clients locaux, cependant, n'ont pas cette restriction.
Timer Service
97

¨ Obtenir des informations sur des Timers


¤ En plus de définir les méthodes cancel et getHandle, l'interface
Timer définit des méthodes permettant d'obtenir des
informations sur les timers :
¤ La méthode getInfo renvoie l'objet qui était le dernier
paramètre lors de l’invocation de createTimer. Par exemple,
dans l'extrait de code createTimer de la section précédente, ce
paramètre d'information est un objet String avec la valeur
timer créée.
¤ Pour récupérer tous les timers actifs d’un bean, appeler la
méthode getTimers de l’interface TimerService. La méthode
getTimers renvoie une collection d'objets Timer.
Timer Service
98

¨ Obtenir des informations sur des Timers


¤ En plus de définir les méthodes cancel et getHandle, l'interface
Timer définit des méthodes permettant d'obtenir des informations
sur les timers :
public long getTimeRemaining();
public java.util.Date getNextTimeout();
public java.io.Serializable getInfo();

¤ La méthode getInfo renvoie l'objet qui était le dernier paramètre


lors de l’invocation de createTimer. Par exemple, dans l'extrait de
code suivant, ce paramètre d'information est un objet String avec la
valeur «timer created» :
Timer timer = timerService.createTimer(intervalDuration, "timer created");

¤ Pour récupérer tous les timers actifs d’un bean, appeler la méthode
getTimers de l’interface TimerService. La méthode getTimers
renvoie une collection d'objets Timer.
Timer Service
99

¨ Timersession Exemple
¤ TimerSessionBean est un bean de session singleton qui montre comment
définir à la fois un timer automatique et un timer programmatique.
¤ Dans le code source de TimerSessionBean qui suit, les méthodes setTimer
et @Timeout sont utilisées pour définir un timer programmatique.
¤ Une instance de TimerService est injectée par le conteneur lors de la
création du bean. Comme il s’agit d’une méthode métier, setTimer est
exposé à la vue locale, sans interface, de TimerSessionBean et peut être
appelé par le client.
¤ Dans cet exemple, le client appelle setTimer avec une durée d'intervalle
de 8 000 millisecondes ou 8 secondes. La méthode setTimer crée un
nouveau minuteur en appelant la méthode createTimer de TimerService.
¤ Maintenant que le timer est défini, le conteneur EJB appellera la méthode
programmaticTimeout de TimerSessionBean à l'expiration du minuteur,
dans environ 8 secondes .
Timer Service
100

¨ Timersession Exemple
¤ TimerSessionBean a également une méthode de minuterie et de
délai automatique, automaticTimeout.
¤ Le Timer automatique est configuré pour expirer toutes les
minutes et est défini à l'aide d'une expression de timer basée
sur un calendrier dans l'annotation @Schedule .
¤ TimerSessionBean a également deux méthodes métier:
getLastProgrammaticTimeout et getLastAutomaticTimeout.
¤ Les clients appellent ces méthodes pour obtenir la date et
l'heure du dernier délai d'expiration respectivement pour le
timer programmatique et le timer automatique.
¤ Voici le code source de la classe TimerSessionBean:
Timer Service : Timersession
Exemple
101

package exemplejavaee.timersession.ejb;

import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;

/**
* TimerBean is a singleton session bean that creates a timer and prints out a
* message when a timeout occurs.
*/
@Singleton
@Startup
public class TimerSessionBean {
@Resource
TimerService timerService;
private Date lastProgrammaticTimeout;
private Date lastAutomaticTimeout;

private static final Logger logger = Logger.getLogger("timersession.ejb.TimerSessionBean");


Timer Service : Timersession
Exemple
102
public void setTimer(long intervalDuration) {
logger.log(Level.INFO, "Setting a programmatic timeout for {0} milliseconds from now.",
intervalDuration);
Timer timer = timerService.createTimer(intervalDuration, "Created new programmatic
timer");
}

@Timeout
public void programmaticTimeout(Timer timer) {
this.setLastProgrammaticTimeout(new Date());
logger.info("Programmatic timeout occurred.");
}

@Schedule(minute = "*/1", hour = "*", persistent = false)


public void automaticTimeout() {
this.setLastAutomaticTimeout(new Date());
logger.info("Automatic timeout occurred");
}

/**
* @return the lastTimeout
*/
public String getLastProgrammaticTimeout() {
if (lastProgrammaticTimeout != null) {
return lastProgrammaticTimeout.toString();
} else {
return "never";
}
}
Timer Service : Timersession
Exemple
103

/**
* @param lastTimeout the lastTimeout to set
*/
public void setLastProgrammaticTimeout(Date lastTimeout) {
this.lastProgrammaticTimeout = lastTimeout;
}

/**
* @return the lastAutomaticTimeout
*/
public String getLastAutomaticTimeout() {
if (lastAutomaticTimeout != null) {
return lastAutomaticTimeout.toString();
} else {
return "never";
}
}

/**
* @param lastAutomaticTimeout the lastAutomaticTimeout to set
*/
public void setLastAutomaticTimeout(Date lastAutomaticTimeout) {
this.lastAutomaticTimeout = lastAutomaticTimeout;
}
}
Timer Service : Timersession
Exemple
104

package exemplejavaee.timersession.web;

import java.io.Serializable;
import exemplejavaee.timersession.ejb.TimerSessionBean;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
@Named
@SessionScoped
public class TimerManager implements Serializable {
@EJB
private TimerSessionBean timerSession;
private String lastProgrammaticTimeout;
private String lastAutomaticTimeout;

/** Creates a new instance of TimerManager */


public TimerManager() {
this.lastProgrammaticTimeout = "never";
this.lastAutomaticTimeout = "never";
}
public String getLastProgrammaticTimeout() {
lastProgrammaticTimeout = timerSession.getLastProgrammaticTimeout();
return lastProgrammaticTimeout;
}
Timer Service : Timersession
Exemple
105

public void setLastProgrammaticTimeout(String lastTimeout) {


this.lastProgrammaticTimeout = lastTimeout;
}
public void setTimer() {
long timeoutDuration = 8000;
timerSession.setTimer(timeoutDuration);
}
public String getLastAutomaticTimeout() {
lastAutomaticTimeout = timerSession.getLastAutomaticTimeout();
return lastAutomaticTimeout;
}
public void setLastAutomaticTimeout(String lastAutomaticTimeout) {
this.lastAutomaticTimeout = lastAutomaticTimeout;
}
}
Timer Service : Timersession
Exemple
106

<?xml version='1.0' encoding='UTF-8' ?>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<body>
<h2>Timer</h2>
<p>The last programmatic timeout was: #{timerManager.lastProgrammaticTimeout}.</p>
<p>The last automatic timeout was: #{timerManager.lastAutomaticTimeout}</p>
<p>Set a programmatic timer here.</p>
<h:form>
<h:commandButton value="Set Timer" action="#{timerManager.setTimer}" />
<h:commandButton value="Refresh" action="timer-client"/>
</h:form>
</body>
</html>
Timer Service
107

¨ Timersession Exemple
¤ Déployer et exécuter le projet
¤ Cliquer sur Définir la minuterie pour
définir une minuterie programmatique.
¤ Attendre un moment et cliquer sur le
bouton Actualiser du navigateur. La
date et l'heure des derniers délais
d'expiration programmatique et
automatique sera afficher.
¤ Pour voir les messages consignés lors
d'un dépassement de délai, ouvrir le
fichier server.log situé dans le
répertoire domain/logs/ .
Gestion des exceptions
108

¨ Les exceptions levées par les beans enterprise appartiennent à deux


catégories: système et application.
¤ Une exception système indique un problème avec les services prenant en charge une
application. Par exemple, une connexion à une ressource externe ne peut pas être
obtenue ou une ressource injectée est introuvable. S'il rencontre un problème au niveau
du système, votre bean enterprise doit générer une exception
javax.ejb.EJBException. Etant donné que EJBException est une sous-classe de
RuntimeException, vous n’avez pas besoin de le spécifier dans la clause throws de la
déclaration de méthode. Si une exception système est levée, le conteneur EJB peut
détruire l'instance de bean. Par conséquent, une exception système ne peut pas être
gérée par le programme client du bean, mais nécessite l'intervention d'un
administrateur système.
¤ Une exception d'application signale une erreur dans la logique métier d'un bean
enterprise. Les exceptions d’application sont généralement des exceptions que vous
avez vous-même codées, telles que l’exception BookException générée par les
méthodes commerciales de l’exemple CartBean. Lorsqu'un bean entreprise lève une
exception d'application, le conteneur ne l'enveloppe pas dans une autre exception. Le
client doit pouvoir gérer toutes les exceptions d'application reçues.
¤ Si une exception système se produit dans une transaction, le conteneur EJB annule la
transaction. Toutefois, si une exception d'application est levée au sein d'une
transaction, le conteneur n'annule pas la transaction.
Invocation de méthode asynchrone
109
¨ Les beans session peuvent implémenter des méthodes métier asynchrones dans
lesquelles le contrôle est renvoyé au client par le conteneur de beans enterprise avant
que la méthode ne soit appelée sur l'instance de bean session.
¨ Les clients peuvent ensuite utiliser l'API de concurrence Java SE pour récupérer le résultat,
annuler l'appel et rechercher des exceptions.
¨ Les méthodes asynchrones sont généralement utilisées pour les opérations de longue
durée, les tâches gourmandes en ressources du processeur, les tâches en arrière-plan,
pour augmenter le débit de l'application ou pour améliorer le temps de réponse de
l'application si le résultat de l'appel de la méthode n'est pas requis immédiatement.
¨ Lorsqu'un client de session bean appelle une méthode métier typique non asynchrone, le
contrôle n'est pas renvoyé au client tant que la méthode n'est pas terminée.
¨ Toutefois, les clients appelant des méthodes asynchrones se voient immédiatement
redonner le contrôle par le conteneur de beans entreprise.
¨ Cela permet au client d’exécuter d’autres tâches pendant l’appel de la méthode.
¨ Si la méthode retourne un résultat, le résultat est une implémentation de l'interface
java.util.concurrent.Future <V>, où "V" est le type de valeur du résultat.
¨ L’interface Future <V> définit les méthodes que le client peut utiliser pour vérifier si le
calcul est terminé, attendre que l’appel soit terminé, récupérer le résultat final et annuler
l’appel.
Invocation de méthode asynchrone
110

¨ Création d'une méthode métier asynchrone


¤ Utiliser l’annotation @Asynchronous de javax.ejb.Asynchronous
au niveau :
n D’une méthode pour la marquer en tant que méthode asynchrone;
n De la classe pour marquer toutes les méthodes métier du bean session en
tant que méthodes asynchrones.
¤ Les méthodes de bean session exposant les Web-services ne
peuvent pas être asynchrones.
¤ Les méthodes asynchrones doivent renvoyer void ou une
implémentation de l'interface Future <V>.
¤ Les méthodes asynchrones qui retournent void ne peuvent pas
déclarer d’exceptions d’application, mais si elles renvoient Future
<V>, elles peuvent déclarer des exceptions d’application.
@Asynchronous
public Future<String> processPayment(Order order) throws PaymentException { ... }
Invocation de méthode asynchrone
111

¨ Création d'une méthode métier asynchrone


¤ La méthode ci-dessous tentera de traiter le paiement d'une commande et
renverra le statut sous forme de chaîne de caractères.
¤ Même si le processus de paiement prend beaucoup de temps, le client
peut continuer à travailler et afficher le résultat à la fin du traitement.
¤ La classe javax.ejb.AsyncResult <V> est une implémentation concrète de
l'interface Future <V> fournie en tant que classe auxiliaire pour renvoyer
des résultats asynchrones.
¤ AsyncResult a un constructeur avec le résultat en tant que paramètre, ce
qui facilite la création d'implémentations Future <V>.
¤ Par exemple, la méthode processPayment utiliserait AsyncResult pour
renvoyer le statut sous forme de chaîne:
@Asynchronous
public Future<String> processPayment(Order order) throws PaymentException {
...
String status = ...;
return new AsyncResult<String>(status);
}
Invocation de méthode asynchrone
112

¨ Création d'une méthode métier asynchrone


¤ Le résultat est renvoyé au conteneur de beans enterprise, et
non pas directement au client, qui le met à la disposition du
client.
¤ Le bean session peut vérifier si le client a demandé l'annulation
de l'appel en appelant la méthode
javax.ejb.SessionContext.wasCancelled. Par exemple:
@Asynchronous
public Future<String> processPayment(Order order) throws PaymentException {
...
if (SessionContext.wasCancelled()) {
// clean up
} else {
// process the payment
}
...
}
Invocation de méthode asynchrone
113

¨ Appel de méthodes asynchrones à partir de clients Enterprise Bean


¤ Les clients de session bean appellent des méthodes asynchrones
exactement comme des méthodes métiers non asynchrones.
¤ Si la méthode asynchrone renvoie un résultat, le client reçoit une instance
Future <V> dès que la méthode est appelée.
¤ Cette instance peut être utilisée pour extraire le résultat final, annuler
l'invocation, vérifier si l'invocation est terminée, vérifier si des exceptions
ont été générées lors du traitement et vérifier si l'invocation a été annulée.

@Asynchronous
public Future<String> processPayment(Order order) throws PaymentException {
...
if (SessionContext.wasCancelled()) {
// clean up
} else {
// process the payment
}
...
}
Invocation de méthode asynchrone
114

¨ Récupérer le résultat final d'une invocation de méthode asynchrone


¤ Le client peut récupérer le résultat en utilisant l’une des méthodes Future <V>.get.
Si le traitement n’a pas été terminé par le bean session gérant l’invocation, l’appel
d’une des méthodes get entraîne l’arrêt de l’exécution du client jusqu’à ce que
l’invocation soit terminée. Utiliser la méthode Future <V>.isDone pour déterminer
si le traitement est terminé avant d'appeler l'une des méthodes get.
¤ La méthode get () renvoie le résultat sous le type spécifié dans la valeur de type
de l'instance Future <V>. Par exemple, appeler Future <String> .get () renverra
un objet String. Si l'appel de méthode est annulé, les appels à get () entraînent la
génération d'une exception java.util.concurrent.CancellationException. Si
l'appel a entraîné une exception lors du traitement par le bean session, les appels
à get () génèrent une exception java.util.concurrent.ExecutionException. La
cause de l'exception ExecutionException peut être extraite en appelant la
méthode ExecutionException.getCause.
¤ La méthode get (long timeout, java.util.concurrent.TimeUnit unit) est similaire à
la méthode get (), mais permet au client de définir une valeur de délai d'attente.
Si la valeur du délai d'attente est dépassée, une exception
java.util.concurrent.TimeoutException est levée. Voir Javadoc pour la classe
TimeUnit pour connaître les unités de temps disponibles pour spécifier la valeur
de délai d'attente.
Invocation de méthode asynchrone
115

¨ Annuler une invocation de méthode asynchrone


¤ Appeler la méthode cancel (boolean mayInterruptIfRunning) sur
l'instance Future <V> pour tenter d'annuler l'invocation de la méthode. La
méthode cancel renvoie true si l'annulation a abouti et false si l'invocation
de méthode ne peut pas être annulée.
¤ Lorsque l'invocation ne peut pas être annulée, le paramètre
mayInterruptIfRunning est utilisé pour alerter l'instance de bean de
session sur laquelle est invoquée la méthode, que le client a tenté
d'annuler l'invocation. Si mayInterruptIfRunning est défini sur true, les
appels à SessionContext.wasCancelled par l'instance de bean session
renverront true. Si mayInterruptIfRunning doit définir la valeur false, les
appels à SessionContext.wasCancelled par l'instance du bean session
renverront false.
¤ La méthode Future <V> .isCancelled est utilisée pour vérifier si l'appel
de méthode a été annulé avant l'appel de méthode asynchrone soit
terminé en appelant Future <V> .cancel. La méthode isCancelled renvoie
true si l'invocation a été annulée.
Invocation de méthode asynchrone
116

¨ Vérification de l'état d'une invocation de méthode


asynchrone
¤ La méthode Future <V> .isDone renvoie true si l'instance du
bean session a terminé le traitement de l'appel de la méthode.
¤ La méthode isDone renvoie true si l'invocation de méthode
asynchrone s'est terminée normalement, a été annulée ou a
entraîné une exception. C'est-à-dire que isDone indique
uniquement si le bean session a terminé le traitement de
l'appel.
Invocation de méthode asynchrone :
Exemple
117

¨ Le module async-war se compose d'un unique bean de


session sans état, MailerBean, et d’une application front-
end Web JavaServer Faces qui affiche un formulaire
permettant aux utilisateurs de saisir l'adresse e-mail du
destinataire d'un e-mail. Le statut de l'email est mis à jour
lorsque l'email est finalement envoyé.
¨ Le bean session MailerBean injecte une ressource JavaMail
utilisée pour envoyer un message électronique à une
adresse spécifiée par l'utilisateur. Le message est créé,
modifié et envoyé à l'aide de l'API JavaMail.
¨ Le bean session ressemble à ceci:
Invocation de méthode asynchrone :
Exemple
118
package exemplejavaee.async.ejb;

import java.text.DateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.AsyncResult;
import javax.ejb.Asynchronous;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

@Named
@Stateless
public class MailerBean {
@Resource(name = "mail/myExampleSession")
private Session session;
private static final Logger logger = Logger.getLogger(MailerBean.class.getName());
@Asynchronous
public Future<String> sendMessage(String email) {
String status;
Invocation de méthode asynchrone :
Exemple
119
try {
Properties properties = new Properties();
properties.put("mail.smtp.port", "3025");
session = Session.getInstance(properties);
Message message = new MimeMessage(session);
message.setFrom();
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email,
false));
message.setSubject("Test message from asynchrone example");
message.setHeader("X-Mailer", "JavaMail");
DateFormat dateFormatter = DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat. LONG);
Date timeStamp = new Date();
String messageBody = "This is a test message from the asynchrone "
+ "example of the Java EE. It was sent on " + dateFormatter.format(timeStamp) +
".";
message.setText(messageBody);
message.setSentDate(timeStamp);
Transport.send(message);
status = "Sent";
logger.log(Level.INFO, "Mail sent to {0}", email);
} catch (MessagingException ex) {
logger.severe("Error in sending message.");
status = "Encountered an error: " + ex.getMessage();
logger.severe(ex.getMessage());
}
return new AsyncResult<>(status);
}
}
Invocation de méthode asynchrone :
Exemple
120
package exemplejavaee.async.web;

import java.io.Serializable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.logging.Logger;
import exemplejavaee.async.ejb.MailerBean;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named
@SessionScoped
public class MailerManagedBean implements Serializable {
private static final long serialVersionUID = 1L;

@EJB
protected MailerBean mailerBean;
protected String email;
protected String status;
private Future<String> mailStatus;

private static final Logger logger = Logger.getLogger(MailerManagedBean.class.getName());

public MailerManagedBean() {
}
Invocation de méthode asynchrone :
Exemple
121
public String getStatus() {
if (mailStatus.isDone()) {
try {
this.setStatus(mailStatus.get());
} catch (ExecutionException | CancellationException | InterruptedException ex) {
this.setStatus(ex.getCause().toString());
}
}
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String send() {
try {
mailStatus = mailerBean.sendMessage(this.getEmail());
this.setStatus("Processing... (refresh to check again)");
} catch (Exception ex) {
logger.severe(ex.getMessage());
}
return "response?faces-redirect=true";
}
}
Invocation de méthode asynchrone :
Exemple
122

package exemplejavaee.async.smtp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server implements Runnable {

private final Socket client;

public static void main(String[] args) throws IOException {


ServerSocket server = new ServerSocket(3025);
System.out.println("[Test SMTP server listening on port 3025]");
while (true) {
Socket client = server.accept();
Thread sthread = new Thread(new Server(client));
sthread.start();
}
}

public Server(Socket client) {


this.client = client;
}
Invocation de méthode asynchrone :
Exemple
123
@Override
public void run() {
String inline; String msg = "";
try {
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
InputStreamReader isr = new InputStreamReader(client.getInputStream());
BufferedReader in = new BufferedReader(isr);
System.out.println("[Client connected]");

out.println("220 exemplejavaee.asyncsmtp");
inline = in.readLine();
if (inline.split(" ")[0].compareTo("HELO") != 0 &&
inline.split(" ")[0].compareTo("EHLO") != 0) {
client.close(); return;
}

out.println("250 +OK SMTP server Ready");


inline = in.readLine();
if (inline.split(":")[0].compareTo("MAIL FROM") != 0) {
client.close(); return;
}

out.println("250 +OK Sender OK");


inline = in.readLine();
if (inline.split(":")[0].compareTo("RCPT TO") != 0) {
client.close(); return;
}
Invocation de méthode asynchrone :
Exemple
124

out.println("250 +OK Recipient OK");


inline = in.readLine();
if (!inline.contains("DATA")) {
client.close(); return;
}

out.println("354 +OK Start mail input.");


while ((inline = in.readLine()) != null) {
if (inline.compareTo(".") == 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) { }
out.println("250 +OK Requested action completed.");
in.readLine();
client.close();
System.out.println("[Delivering message...]");
System.out.println(msg);
System.out.println("\n");
} else
msg = msg + inline + "\n";
}
} catch (IOException e) { }
}
}
Invocation de méthode asynchrone :
Exemple
125

<!-- index.xhtml -->

<?xml version='1.0' encoding='UTF-8' ?>


<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<h:outputStylesheet library="css" name="default.css" />
<title>asynchrone Example</title>
</h:head>
<h:body>
<h:form id="emailForm">
<h:panelGrid id="emailFormGrid" columns="3">
<h:outputLabel for="emailInputText" value="Send email to: " />
<h:inputText id="emailInputText" value="${mailerManagedBean.email}" />
<h:message for="emailInputText" />
<f:facet name="footer">
<h:panelGroup style="display:block; text-align:center">
<h:commandButton id="sendButton" action="#{mailerManagedBean.send}" value="Send email" />
<h:commandButton id="cancel" immediate="true" action="index" value="Cancel" />
</h:panelGroup>
</f:facet>
</h:panelGrid>
</h:form>
</h:body>
</html>
Invocation de méthode asynchrone :
Exemple
126

<!-- response.xhtml -->

<?xml version='1.0' encoding='UTF-8' ?>


<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<h:outputStylesheet library="css" name="default.css" />
<title>asynchrone Example</title>
</h:head>
<h:body>
<h:outputText id="messageStatus"
value="#{mailerManagedBean.status}" />
</h:body>
</html>
Invocation de méthode asynchrone :
Exemple
127
¨ La ressource JavaMail injectée peut être configurée via la console d'administration du serveur:
¤ Ouvrir l'URL suivant: http://localhost:4848/
¤ Sélectionner le nœud JavaMail Sessions et cliquer sur new pour définir la ressource JavaMail
mail/myExampleSession.
¤ Pour supprimer la ressource JavaMail, utiliser l’invite de commande :

¨ Exécuter le projet «ejb-asynchrone-smtp»


¨ Déployer et Exécuter le projet «ejb-asynchrone-web».
Invocation de méthode asynchrone :
Exemple
128

<!-- response.xhtml -->

<?xml version='1.0' encoding='UTF-8' ?>


<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<h:outputStylesheet library="css" name="default.css" />
<title>asynchrone Example</title>
</h:head>
<h:body>
<h:outputText id="messageStatus"
value="#{mailerManagedBean.status}" />
</h:body>
</html>

Vous aimerez peut-être aussi