EJB File - Plateforme e-learning Moodle de l`INSA de Rouen
Transcription
EJB File - Plateforme e-learning Moodle de l`INSA de Rouen
INSA - ASI InfoRep : EJB Informatique Répartie Introduction aux EJB Alexandre Pauchet INSA Rouen - Département ASI BO.B.RC.18, [email protected] 1/65 INSA - ASI InfoRep : EJB 2/65 Plan 1 2 3 4 5 6 Introduction 7 Callbacks 8 EJB Session avec état 9 EJB/JSP 10 Persistance 11 Les EJB message Architecture J2EE EJB EJB Session sans état Envoi d’exception Passage d’objets par valeur INSA - ASI InfoRep : EJB Introduction (1/3) Historique (rappel) Années 70 : architectures Mainframe (1 tier) Années 80 : architectures 2 tiers (BD) Fin des années 80 : architectures 3 tiers (RPC) Années 90 : architectures 3 tiers Objet (RMI/Corba) Années 00 : architectures orientées services (Web Services) Fin des années 00 : architectures orientées ressources (RESTful) 3/65 INSA - ASI InfoRep : EJB Introduction (2/3) Histoire Aspect programmation Années 70-80 : Programmation procédurale alors que les premiers langages objets datent de la fin des années 60 ! Années 90 : Programmation objet Fin des années 90 : Programmation par composants Les composants peuvent être physiquement distants Si changement, pas besoin de tout recompiler et de tout relinker Bonne programmation objet : seules les interfaces sont connues 4/65 INSA - ASI InfoRep : EJB Introduction 5/65 (3/3) J2EE Volonté de SUN Cadre de développement par composants avec services J2EE (Java 2 Edition Enterprise), qui propose des API : L’invocation de méthodes distantes : RMI, CORBA, Web Services L’accès aux bases de données relationnelles : JDBC L’accès aux annuaires et services de nommage : JNDI L’utilisation du XML : DOM et SAX HTML dynamique et traitement de requêtes HTTP : JSP et Servlet La gestion du Mail : Java Mail La gestion des composants : EJB La gestion des messages entre composants : Java Message Service La gestion des droits d’accès : Java Authentication and Authorization Service (JAAS) INSA - ASI Architecture J2EE InfoRep : EJB (1/4) Description de l’architecture J2EE 6/65 INSA - ASI InfoRep : EJB Architecture J2EE 7/65 (2/4) Rappels : J2EE et les conteneurs Web La spécification J2EE fournit les éléments suivants pour la conception et la réalisation d’application Web : Servlets Java et JSP Les servlets et JSP constituent les blocs de construction du développement d’applications web avec J2EE En terme J2EE, les servlets et pages JSP sont des composants web Application web Collection de servlets et de pages JSP, d’autres classes annexes ou de bibliothèques de classes, ainsi que des ressources statiques telles que des documents HTML, XHTML ou XML, images, etc. Conteneur web Essentiellement un environnement d’exécution Java pour les applications web Responsable de l’initialisation, de l’invocation et de la gestion de la durée de vie des servlets Java et des pages JSP INSA - ASI InfoRep : EJB Architecture J2EE 8/65 (3/4) Rappels : J2EE et les conteneurs Web Éléments de la spécification J2EE (suite) : structure de paquetage et descripteur de déploiement le descripteur de déploiement est un fichier XML Application web Application web Servlets Servlets Page JSP Page JSP Classes Java Archives Classes Java Archives Description de déploiement Description de déploiement Conteneur web INSA - ASI InfoRep : EJB Architecture J2EE (4/4) Rappels : J2EE et les conteneurs Web Exemple de conteneur Web Tomcat http://www.apache.org 9/65 INSA - ASI InfoRep : EJB Les EJB 10/65 (1/11) Description Un composant EJB est constitué d’une collection de classes/interfaces Java Les classes Java doivent respecter certaines règles (Spécifications) Le composant EJB s’exécute dans un conteneur EJB, qui prend en charge tout ce qui concerne le niveau système Répartition des tâches entre le programmeur d’EJB et le conteneur Les composant EJB fonctionnent avec tout type de client : servlets et JSP clients Java (via RMI) clients et serveur divers (via RMI-IIOP, Services Web) ... 3 types d’EJB : entité, session, message INSA - ASI InfoRep : EJB Les EJB 11/65 (2/11) Variétés d’EJB : les EJB entité Représentation orientée objet de données dans une base de données Les clients peuvent y accéder en toute sécurité simultanément La durée de vie de l’EJB est exactement identique à celle des données qu’il représente La relation d’un EJB entité avec les données de la base de données peut être gérée par le programmeur : persistance gérée par l’EJB le conteneur : persistance gérée par le conteneur Cette distinction se révélera souvent essentielle du point de vue des performances Cependant on peut utiliser n’importe quel type d’EJB de manière interchangeable dans la conception INSA - ASI InfoRep : EJB Les EJB 12/65 (3/11) Variétés d’EJB : les EJB session Client unique (extension du client sur le serveur) Fournit de la logique métier (calcul d’un taux, panier d’un client, etc.) La durée de vie de l’EJB ne doit pas dépasser celle de son client Représente la logique métier Seuls EJB interfaçable par les clients Les EJB session sans état ne possède aucune information sur son client ex : EJB relatif à une calculatrice Les EJB session avec état peut conserver des informations au nom de son client ex : EJB relatif à un panier d’achat électronique INSA - ASI InfoRep : EJB Les EJB 13/65 (4/11) Variétés d’EJB : les EJB message EJB producteur ou consommateur de messages Utilisation de JMS (le server d’application est un JMS provider, et les EJB sont des JMS client : JMS producer et JMS consumer) Permet l’envoi de messages asynchrones Permet l’envoi multiple (1 → n) INSA - ASI InfoRep : EJB Les EJB 14/65 (5/11) Les conteneurs EJB Conteneur = environnement d’exécution pour un composant Le composant se trouve dans le conteneur Le conteneur fournit des services au composant Conteneur se trouve dans un serveur d’applications qui lui fournit un environnement d’exécution Conteneur web Conteneur EJB Serveur d’applications INSA - ASI InfoRep : EJB Les EJB 15/65 (6/11) Les services des conteneurs EJB Sans écrire une seule ligne de code Persistance. Possibilité pour l’EJB d’être persistant dans une BD Transactions déclaratives. Possibilité de gérer des transactions complexes (sans utiliser l’API JTA -Java Transaction- et JTS -Java Transaction Service-) Mémoire cache. Possibilité d’améliorer les performances Sécurité déclarative. Possibilité de gérer l’accès aux composants Gestion d’erreurs. La spécification EJB définit la manière dont les erreurs affectent les transactions, les résultats au niveau client, la connexion et la restauration des composants Portabilité. EJB = Spécification = possibilité de porter un EJB sur un autre serveur plus puissant INSA - ASI InfoRep : EJB Les EJB (7/11) Comment le conteneur fournit-il ces services ? 3 concepts de bases pour les EJB Le concept de contrat Services orthogonaux aux EJB Interposition du conteneur entre le client et l’EJB Contrat Répartition des responsabilités entre chaque couche du logiciel (Client, Conteneur, EJB, Gestionnaire de persistance (≥ 2.0)) Services orthogonaux Le conteneur EJB fournit des services au programmeur Le programmeur de l’EJB n’a plus qu’à respecter les règles pour exploiter automatiquement ces services Ces règles sont spécifiées dans le descripteur de déploiement 16/65 INSA - ASI InfoRep : EJB Les EJB 17/65 (8/11) Interposition Votre EJB Classe d’interposition générée par le conteneur Skeleton RMI Réseau Stub RMI Client Interposition : RMI et le design pattern Remote Proxy 1 Le client exécute un appel sur un Stub RMI 2 Ce stub RMI assemble et envoie des informations au serveur 3 Le skeleton désassemble les paramètres et les transmets au conteneur EJB 4 Le conteneur examine les références de sécurité de l’appelant de la méthode 5 Le conteneur démarre ou rejoint toute transaction nécessaire 6 Le conteneur exécute tous les appels nécessaires aux fonctions de persistance 7 Le conteneur déclenche diverses méthodes callback pour permettre au composant EJB d’acquérir des ressources 8 La méthode “logique métier” est appelée 9 Le conteneur exécute quelques autres tâches relatives aux transactions, à la persistance, aux méthodes callback 10 Le conteneur renvoie le résultat de la méthode métier ou une exception au client INSA - ASI InfoRep : EJB Les EJB 18/65 (9/11) Annotations Java Intégrées au JDK 1.5, elles permettent d’ajouter des Méta-informations au code (i.e. marquer des éléments Java afin de leur ajouter une propriété) Peuvent être utilisées sur n’importe quel type d’élément Java (package, class, attribut, méthode, paramètre, etc.) Plusieurs annotations peuvent être utilisées sur un même élément Non prises en compte par la JVM (mais présente dans le .class) : il faut écrire du code ou des outils qui utilise ces informations Utilisées à la compilation ou à l’exécution Utilisation : @ suivi du mot-clef correspondant à l’annotation L’API Java 5.0 propose de base 3 annotations : @Deprecated, @Override et @SuppressWarnings Déclaration et création de nouvelles annotations : comme une interface en utilisant le mot-clef @interface (java.lang.annotation.Annotation) Possibilité de passer des informations à une annotation : nom=valeur INSA - ASI InfoRep : EJB Les EJB (10/11) Exemple d’annotations Java Exemple p u b l i c @ interface M a N o u v e l l e A n n o t a t i o n { } Exemple @ MaNouvelleAnnotation @ S u p p r e s s Warnings (" deprecation ") p u b l i c c l a s s maClasse { @ U n e A u t re An n ot a ti on ( champ =" type ") p u b l i c String texte = " Texte " ; @ Override @ S u p p r e ssWarnings ({" deprecation " ," unchecked "}) p u b l i c String toString () { r e t u r n t h i s . texte ; } } 19/65 INSA - ASI InfoRep : EJB Les EJB (11/11) EJB3 et les annotations Les EJB3 utilisent les annotations pour simplifier le code à produire : Moins de code à écrire Génération automatique des descripteurs de déploiement 20/65 INSA - ASI InfoRep : EJB Les EJB Session sans état (1/7) Description EJB Session sans état (Stateless) Composé d’une ou deux interfaces et d’une classe métier : Interface de description du contrat pour accès distant (XXRemote.java) Utilisation de l’annotation @Remote (importation de javax.ejb.Remote) juste avant la définition de l’interface Interface de description du contrat pour accès local (XXLocal.java) Utilisation de l’annotation @Local (importation de javax.ejb.Local) juste avant la définition de l’interface Classe de définition de la logique métier (XXBean.java) Importation de javax.ejb.Stateless Utilisation de l’annotation @Stateless avant la définition de classe Implémentation des interfaces précédentes Ne pas être final 21/65 INSA - ASI InfoRep : EJB Les EJB Session sans état 22/65 (2/7) Cycle de vie 1 Dans XXXBean.java @PostConstruct suivi de la méthode postConstruct @PreDestroy suivi de la méthode preDestroy 1. extrait du tutoriel de SUN : http://java.sun.com/j2ee/tutorial/1_3-fcs/ doc/EJBConcepts9.html INSA - ASI InfoRep : EJB Les EJB Session sans état Côté serveur HelloStatelessRemote.java package HelloWorld ; i m p o r t javax . ejb . Remote ; @ Remote public i n t e r f a c e H e l l o S t a t e l e s s R e m o t e { p u b l i c String sayHello ( String s ) ; } HelloStatelessLocal.java package HelloWorld ; i m p o r t javax . ejb . Local ; @ Local public i n t e r f a c e H e l l o St a t e l e s s L oc a l { p u b l i c String sayHello ( String s ) ; } (3/7) 23/65 INSA - ASI InfoRep : EJB Les EJB Session sans état (4/7) Côté serveur HelloStatelessBean.java package HelloWorld ; i m p o r t javax . ejb . Stateless ; @ Stateless public c l a s s H el l oS ta t el e ss Be a n i m p l e m e n t s HelloStatelessLocal , H e l l o S t a t e l e s s R e m o t e { p u b l i c String sayHello ( String s ) { r e t u r n " Hello " + s + " ! " ; } } @Local et @Remote peuvent être portées par la même interface Il faut au moins une annotation @Local ou @Remote Toutes les annotations peuvent éventuellement être placées directement dans l’EJB. L’interface doit alors être précisé : @ Stateless @ Remote ( NomInterface . class ) p u b l i c c l a s s EJBStateless i m p l e m e n t s NomInterface { ... } 24/65 INSA - ASI InfoRep : EJB Les EJB Session sans état (5/7) Déploiement avec JBoss Compilation et déploiement A la compilation, inclure dans le classpath : JBOSS_DIR/modules/javax/ejb/api/main/jboss-ejb-api_3.1_ spec-1.0.1.Final.jar (JBoss) JBOSS_DIR/modules/system/layers/base/javax/ejb/api/main/ jboss-ejb-api_3.2_spec-1.0.0.Final.jar (WildFly) Mettre dans un .jar Pour déployer, déposer dans le répertoire JBOSS DIR/server/JBOSS MODE/deploy (JBoss < 7) JBOSS DIR/standalone/deployments (JBoss 7 et plus) Arborescence des répertoires HelloStateless.jar |_ HelloWorld | |_ HelloStatelessLocal.class | |_ HelloStatelessBean.class |_ META-INF |_ MANIFEST.MF 25/65 INSA - ASI InfoRep : EJB Les EJB Session sans état (6/7) Côté client Nommage d’un EJB Service de nommage : JNDI Nommage d’un EJB : ejb:AppName(ear)/ModuleName(jar)/BeanName!InterfaceName Client.java import import import import javax . naming . Context ; javax . naming . InitialContext ; java . util . Hashtable ; HelloWorld . H e l l o S t a t e l e s s R e m o t e ; p u b l i c c l a s s Client { p u b l i c s t a t i c v o i d main ( String [] args ) { try { Hashtable jndiProperties = new Hashtable () ; jndi Properties . put ( Context . URL_PKG_PREFIXES , " org . jboss . ejb . client . naming " ) ; Context context = new InitialContext ( jndiProperties ) ; H e l l o S t a t e l e s s R e m o t e obj = ( H e l l o S t a t e l e s s R e m o t e ) context . lookup ( " ejb :/ HelloStateless / He l lo St a te le s sB e an ! HelloWorld . H e l l o S t a t e l e s s R e m o t e " ) ; System . out . println ( obj . sayHello ( args [0]) ) ; } c a t c h ( Exception e ) { System . out . println ( e ) ; e . p ri ntStackTrace () ; } } } 26/65 INSA - ASI InfoRep : EJB Les EJB Session sans état (7/7) Exécution Client À l’exécution, inclure dans le classpath : JBOSS_DIR/bin/client/jboss-client.jar jboss-ejb-client.properties jboss-ejb-client.properties endpoint . name = client - endpoint remote . c o n n e c t io np r ov id e r . create . options . org . xnio . Options . SSL_ENABLED = f a l s e remote . connections = d e f a u l t remote . connection . d e f a u l t . host = localhost remote . connection . d e f a u l t . port = 8080 remote . connection . d e f a u l t . connect . options . org . xnio . Options . S A S L _ P O L I C Y _ N O A N O N Y M O U S = false 27/65 INSA - ASI Envoi d’exception InfoRep : EJB (1/3) Côté serveur EJB : HelloStatelessBean.java package HelloWorld ; i m p o r t javax . ejb . Stateless ; @ Stateless public c l a s s H el l oS ta t el e ss Be a n i m p l e m e n t s H e l l o S t a t e l e s s R e m o t e { p u b l i c String sayHello ( String s ) t h r o w s ChaineVide { i f ( s . length () ==0) { throw new ChaineVide () ; } e l s e i f ( s . equals ( " test " ) ) { s = " " + 1/0; } r e t u r n " Hello " + s + " ! " ; } } 28/65 INSA - ASI Envoi d’exception InfoRep : EJB (2/3) Côté serveur Exception : ChaineVide.java package HelloWorld ; p u b l i c c l a s s ChaineVide e x t e n d s Exception { p u b l i c ChaineVide () { s u p e r ( " String vide ! " ) ; } } Interface : HelloStatelessRemote.java package HelloWorld ; i m p o r t javax . ejb . Remote ; @ Remote public i n t e r f a c e H e l l o S t a t e l e s s R e m o t e { p u b l i c String sayHello ( String s ) t h r o w s ChaineVide ; } 29/65 INSA - ASI InfoRep : EJB Envoi d’exception (3/3) Côté client Client.java import import import import javax . naming . Context ; javax . naming . InitialContext ; java . util . Hashtable ; HelloWorld . H e l l o S t a t e l e s s R e m o t e ; p u b l i c c l a s s Client { p u b l i c s t a t i c v o i d main ( String [] args ) { try { Hashtable jndiProperties = new Hashtable () ; jndi Properties . put ( Context . URL_PKG_PREFIXES , " org . jboss . ejb . client . naming " ) ; Context context = new InitialContext ( jndiProperties ) ; H e l l o S t a t e l e s s R e m o t e obj = ( H e l l o S t a t e l e s s R e m o t e ) context . lookup ( " ejb :/ HelloException / He l lo St a te le s sB e an ! HelloWorld . H e l l o S t a t e l e s s R e m o t e " ) ; i f ( args . length >0) System . out . println ( obj . sayHello ( args [0]) ) ; else System . out . println ( obj . sayHello ( " " ) ) ; } c a t c h ( Exception e ) { System . out . println ( e ) ; e . p ri ntStackTrace () ; } } } 30/65 INSA - ASI InfoRep : EJB Passage d’objets par valeur (1/4) Côté serveur Interface : HelloSerializableRemote.java package HelloWorld ; i m p o r t javax . ejb . Remote ; @ Remote public i n t e r f a c e H e l l o S e r i a l i z a b l e R e m o t e { p u b l i c String sayHello ( Guy g ) ; } EJB : HelloSerializableBean.java package HelloWorld ; i m p o r t javax . ejb . Stateless ; @ Stateless public c l a s s H e l l o S e r i a l i z a b l e B e a n i m p l e m e n t s H e l l o S e r i a l i z a b l e R e m o t e { p u b l i c String sayHello ( Guy g ) { r e t u r n " Hello " + g . getName () + " ! " ; } } 31/65 INSA - ASI InfoRep : EJB Passage d’objets par valeur (2/4) Objet passé Guy.java package HelloWorld ; i m p o r t java . io . Serializable ; p u b l i c c l a s s Guy i m p l e m e n t s Serializable { p r i v a t e String name ; p u b l i c Guy () { t h i s . name = " " ; } p u b l i c Guy ( String name ) { t h i s . name = name ; } p u b l i c String getName () { r e t u r n t h i s . name ; } p u b l i c v o i d setName ( String name ) { t h i s . name = name ; } } 32/65 INSA - ASI InfoRep : EJB Passage d’objets par valeur (3/4) Déploiement Arborescence des répertoires HelloSerializable.jar |_ HelloWorld | |_ HelloSerializableRemote.class | |_ HelloSerializableBean.class | |_ Guy.class |_ META-INF |_ MANIFEST.MF 33/65 INSA - ASI InfoRep : EJB Passage d’objets par valeur 34/65 (4/4) Côté client Client.java import import import import import javax . naming . Context ; javax . naming . InitialContext ; java . util . Hashtable ; HelloWorld . H e l l o S e r i a l i z a b l e R e m o t e ; HelloWorld . Guy ; p u b l i c c l a s s Client { p u b l i c s t a t i c v o i d main ( String [] args ) { try { Hashtable jndiProperties = new Hashtable () ; jndi Properties . put ( Context . URL_PKG_PREFIXES , " org . jboss . ejb . client . naming " ) ; Context context = new InitialContext ( jndiProperties ) ; H e l l o S e r i a l i z a b l e R e m o t e obj = ( H e l l o S e r i a l i z a b l e R e m o t e ) context . lookup ( " ejb :/ He llo Seri ali zab le / H e l l o S e r i a l i z a b l e B e a n ! HelloWorld . H e l l o S e r i a l i z a b l e R e m o t e " ); System . out . println ( obj . sayHello (new Guy ( args [0]) ) ) ; } c a t c h ( Exception e ) { System . out . println ( e ) ; e . p ri ntStackTrace () ; } } } INSA - ASI Callbacks InfoRep : EJB 35/65 (1/6) Exemple Client Programme Serveur Guy EJB Guy Guy File - File - Callback Passage d’un stub RMI INSA - ASI Callbacks InfoRep : EJB (2/6) Côté serveur Interface : HelloCallbackRemote.java package HelloWorld ; i m p o r t javax . ejb . Remote ; i m p o r t java . rmi . RemoteException ; @ Remote public i n t e r f a c e H e l l o Ca l l b a c k R e mo t e { p u b l i c String sayHello ( Guy g ) t h r o w s RemoteException ; } EJB : HelloCallbackBean.java package HelloWorld ; i m p o r t javax . ejb . Stateless ; i m p o r t java . rmi . RemoteException ; @ Stateless public c l a s s He llo Cal lbac kBe an i m p l e m e n t s H e l l o Ca l l b a c k R e mo t e { p u b l i c String sayHello ( Guy g ) t h r o w s RemoteException { r e t u r n " Hello " + g . getName () + " ! " ; } } 36/65 INSA - ASI Callbacks InfoRep : EJB (3/6) Interface du stub paramètre Guy.java package HelloWorld ; i m p o r t java . io . Serializable ; i m p o r t java . rmi . Remote ; i m p o r t java . rmi . RemoteException ; p u b l i c i n t e r f a c e Guy e x t e n d s Remote , Serializable { p u b l i c String getName () t h r o w s RemoteException ; p u b l i c v o i d setName ( String name ) t h r o w s RemoteException ; } L’interface doit être accessible côté client et côté serveur 37/65 INSA - ASI InfoRep : EJB Callbacks (4/6) Déploiement Arborescence des répertoires HelloCallback.jar |_ HelloWorld | |_ HelloCallbackRemote.class | |_ HelloCallbackBean.class | |_ Guy.class |_ META-INF |_ MANIFEST.MF 38/65 INSA - ASI Callbacks InfoRep : EJB 39/65 (5/6) Implémentation du stub côté client uniquement GuyImpl.java package HelloWorld ; i m p o r t java . io .*; p u b l i c c l a s s GuyImpl i m p l e m e n t s Guy { p u b l i c GuyImpl ( String name ) { t h i s . setName ( name ) ; } p u b l i c String getName () { String name = " " ; String fichier = System . getProperty ( " user . dir " ) + " / GuyName " ; try { Buffe redReader br = new BufferedReader (new In put Str eamR ead er (new FileInputStream ( fichier ) ) ) ; name = br . readLine () ; br . close () ; } c a t c h ( IOException ioe ) { ioe . printStackTrace () ; } r e t u r n name ; } p u b l i c v o i d setName ( String name ) { String adr = System . getProperty ( " user . dir " ) + " / GuyName " ; try { Buffe redWriter output =new BufferedWriter (new FileWriter ( adr , f a l s e ) ) ; output . write ( name ) ; output . flush () ; output . close () ; } c a t c h ( IOException ioe ) { ioe . printStackTrace () ; } } } INSA - ASI InfoRep : EJB Callbacks (6/6) Côté client Client.java import import import import import import import javax . naming . Context ; javax . naming . InitialContext ; java . util . Hashtable ; java . rmi . server . U n i c a s t R em o t e O b j e c t ; HelloWorld . H e ll o C a l l b a c kR e m o t e ; HelloWorld . Guy ; HelloWorld . GuyImpl ; p u b l i c c l a s s Client { p u b l i c s t a t i c v o i d main ( String [] args ) { try { Hashtable jndiProperties = new Hashtable () ; jndiProperties . put ( Context . URL_PKG_PREFIXES , " org . jboss . ejb . client . naming " ) ; Context context = new InitialContext ( jndiProperties ) ; H e l l oC a l l b a c k R em o t e obj = ( H el l o C a l l b a ck R e m o t e ) context . lookup ( " ejb :/ HelloCallback / Hel loC all back Bea n ! HelloWorld . He l l o C a l l b ac k R e m o t e " ) ; Guy aGuy = new GuyImpl ( args [0]) , stub = ( Guy ) U n i c a st R e m o t e O b je c t . exportObject ( aGuy ,0) ; System . out . println ( obj . sayHello ( stub ) ) ; U n i c as t R e m o t e O bj e c t . unexportObject ( aGuy , t r u e ) ; } c a t c h ( Exception e ) { System . out . println ( e ) ; } } } 40/65 INSA - ASI InfoRep : EJB Les EJB Session avec état 41/65 (1/6) Description EJB Session avec état (Stateful) Composé d’une ou deux interfaces et d’une classe métier : Interface de description du contrat pour accès distant (XXRemote.java) Utilisation de l’annotation @Remote (importation de javax.ejb.Remote) juste avant la définition de l’interface Interface de description du contrat pour accès local (XXLocal.java) Utilisation de l’annotation @Local (importation de javax.ejb.Local) juste avant la définition de l’interface Classe de définition de la logique métier (XXBean.java) importation de javax.ejb.Stateful Utilisation de l’annotation @Stateful avant la définition de la classe Implémentation des interfaces précédentes Ne pas être final INSA - ASI InfoRep : EJB Les EJB Session avec état 42/65 (2/6) Les EJB session avec état Méthodes liées au cycle de vie a @PostConstruct suivi de la méthode postConstruct @Init suivi de la méthode init @PrePassivate suivi de la méthode prePassivate @PostActivate suivi de la méthode postActivate @Remove suivi de la méthode remove @PreDestroy suivi de la méthode preDestroy a. extrait du tutoriel de SUN : http://java.sun.com/j2ee/tutorial/1_ 3-fcs/doc/EJBConcepts9.html INSA - ASI InfoRep : EJB Les EJB Session avec état (3/6) Côté serveur CounterStatefulLocal.java package Stateful ; i m p o r t javax . ejb . Local ; @ Local public i n t e r f a c e C o u n t e r S t a t e f u l L o c a l { p u b l i c i n t count () ; } CounterStatefulRemote.java package Stateful ; i m p o r t javax . ejb . Remote ; @ Remote public i n t e r f a c e C o u n t e r S t a t e f u l R e m o t e { p u b l i c i n t count () ; } 43/65 INSA - ASI InfoRep : EJB Les EJB Session avec état 44/65 (4/6) Côté serveur CounterStatefulBean.java package Stateful ; i m p o r t javax . ejb . Stateful ; @ Stateful public c l a s s C o u n te r S t a t e f u l Be a n i m p l e m e n t s CounterStatefulLocal , C o u n t e r S t a t e f u l R e m o t e { p r i v a t e i n t counter = 0; p u b l i c i n t count () { r e t u r n ++ t h i s . counter ; } } Compteur session sans état CounterStatelessLocal.class CounterStatelessRemote.class CounterStatelessBean.class INSA - ASI InfoRep : EJB Les EJB Session avec état 45/65 (5/6) Côté client Attention ! Pour un EJB Stateful, une session JNDI doit être créée : on ajoute "?stateful lors de la récupération du stub Client.java p u b l i c s t a t i c v o i d main ( String [] args ) { try { Hashtable jndiProperties = new Hashtable () ; jndiProperties . put ( Context . URL_PKG_PREFIXES , " org . jboss . ejb . client . naming " ) ; Context context = new InitialContext ( jndiProperties ) ; C o u n t e r S t a t e l e s s R e m o t e stateless = ( C o u n t e r S t a t e l e s s R e m o t e ) context . lookup ( " ejb :/ Counter / C o u n t e r S t a t e l e s s B e a n ! Stateless . C o u n t e r S t a t e l e s s R e m o t e " ) ; C o u n t e r S t a t e f u l R e m o t e stateful = ( C o u n t e r S t a t e f u l R e m o t e ) context . lookup ( " ejb :/ Counter / C o un t e r S t a t e fu l B e a n ! Stateful . C o u n t e r S t a t e f u l R e m o t e ? stateful " ) ; System . out . println ( " Decompte System . out . println ( " Decompte System . out . println ( " Decompte System . out . println ( " Decompte } c a t c h ( Exception e ) { System . out . println ( e ) ; e . pr intStackTrace () ; } } ( stateless ) : " + stateless . count () ) ; ( stateless ) : " + stateless . count () ) ; ( stateful ) : " + stateful . count () ) ; ( stateful ) : " + stateful . count () ) ; INSA - ASI InfoRep : EJB Les EJB Session avec état (6/6) Sorties > runClient.sh Decompte (stateless) : 1 Decompte (stateless) : 1 Decompte (stateful) : 1 Decompte (stateful) : 2 46/65 INSA - ASI InfoRep : EJB EJB/JSP (1/6) Archive application J2EE Arborescence des répertoires WebCounter -> WebCounter.ear |_ EJBCounter -> EJBCounter.jar | |_ WebCounterBean.class | |_ WebCounterInterface.class |_ JSPCounter -> JSPCounter.war |_ WEB-INF | |_ web.xml |_ index.jsp |_ counter.jsp 47/65 INSA - ASI EJB/JSP InfoRep : EJB (2/6) Côté serveur WebCounterInterface.java package EJBCounter ; p u b l i c i n t e r f a c e W e b C o un t e r I n t e r fa c e { p u b l i c i n t getCounter () ; } WebCounterBean.java package EJBCounter ; i m p o r t javax . ejb . Stateless ; i m p o r t javax . ejb . Local ; i m p o r t javax . ejb . Remote ; @ Remote ( EJBCounter . W e b Co u n t e r I n t er f a c e . class ) @Stateless public c l a s s WebCounterBean i m p l e m e n t s W e b C ou n t e r I n t e rf a c e { p r i v a t e s t a t i c i n t counter = 0; p u b l i c i n t getCounter () { WebC ounterBean . counter ++; r e t u r n WebCounterBean . counter ; } } 48/65 INSA - ASI InfoRep : EJB EJB/JSP (3/6) Côté client Client.java import import import import javax . naming . Context ; javax . naming . InitialContext ; java . util . Hashtable ; EJBCounter . W e bC o u n t e r I n te r f a c e ; p u b l i c c l a s s Client { p u b l i c s t a t i c v o i d main ( String [] args ) { try { Hashtable jndiProperties = new Hashtable () ; jndiProperties . put ( Context . URL_PKG_PREFIXES , " org . jboss . ejb . client . naming " ) ; Context context = new InitialContext ( jndiProperties ) ; W e b C ou n t e r I n t e rf a c e counter = ( W e b C o u n t e rI n t e r f a c e ) context . lookup ( " ejb : WebCounter / EJBCounter / WebCounterBean ! EJBCounter . We b C o u n t e r I nt e r f a c e " ) ; System . out . println ( " Decompte : " + counter . getCounter () ) ; } c a t c h ( Exception e ) { System . out . println ( e ) ; e . pr intStackTrace () ; } } } 49/65 INSA - ASI EJB/JSP InfoRep : EJB (4/6) Archive Web web.xml <? xml v e r s i o n = " 1.0 " encoding = " utf -8 " ? > <!DOCTYPE web - app PUBLIC " -// Sun Microsystems , Inc .// DTD Web Application 2.3// EN " " http: // java . sun . com / dtd / web - app_2_3 . dtd " > <web - app > < display - name > Archive J2EE </ display - name > < description > Partie Web de ma première application J2EE complète </ description > </ web - app > 50/65 INSA - ASI EJB/JSP InfoRep : EJB (5/6) JSP index.jsp <% @ page contentType = " text / html ; charset = UTF -8 " % > <! DOCTYPE html PUBLIC " -// W3C // DTD XHTML 1.0 Strict // EN " " http :// www . w3 . org / TR / xhtml1 / DTD / xhtml1 - strict . dtd " > < html > < head > < title > JSP Counter </ title > </ head > < body > <h1 > Une page JSP classique ... </ h1 > </ body > </ html > Remarque Appel par http://SERVEUR:PORT/JSPCounter/index.jsp 51/65 INSA - ASI EJB/JSP InfoRep : EJB (6/6) Appel externe counter.jsp <% @ page contentType = " text / html ; charset = UTF -8 " % > <% @ page i m p o r t = " EJBCounter . WebCounterInterface , javax . naming . InitialContext " % > <%! p r i v a t e W e b C o u n t e r I n t e r fa c e counter = n u l l ; p u b l i c v o i d jspInit () { try { counter = ( W e b C ou n t e r I n t e rf a c e ) InitialContext . doLookup ( " ejb : WebCounter / EJBCounter / WebCounterBean ! EJBCounter . W e b C o u nt e r I n t e r f ac e " ) ; } c a t c h ( Exception e ) { e . pr i nt StackTrace () ; } } %> < html > < head > < title > JSP Counter </ title > </ head > < body > <h1 > Hits : <%= counter . getCounter () % > </ h1 > </ body > </ html > 52/65 INSA - ASI InfoRep : EJB Persistance 53/65 (1/11) Concepts Les EJBs entité (Entity) Le gestionnaire d’entités (entity manager ) détermine l’état de chaque objet : créé mais non persistant (pas lié à un contexte de persistance) persistant détaché (sans lien avec le gestionnaire d’entités) supprimé peut être à la charge du conteneur (utilisation direct d’un EntityManager via @PersistenceContext) ou de l’application (création d’un EntityManager par l’intermédiaire une fabrique -EntityManagerFactory- via @PersistenceUnit) Le contexte de persistance ensemble d’entités persistantes (par défaut dans une base de données relationnelles) INSA - ASI InfoRep : EJB Persistance 54/65 (2/11) Les EJB entité La classe représentant l’EJB entité doit Utiliser les annotations @Entity, @Table et @Column Posséder un constructeur par défaut en public ou protected Ne pas être final Implémenter Serializable si détaché Être manipulable uniquement via les accesseurs (les attributs sont private ou protected) Posséder une clef primaire (annotation @Id) : Si simple alors du type : type primitif, classe encapsulant type primitif, String, Date (de java.util ou java.sql) L’annotation @GeneratedValue permet de générer automatiquement cette clef primaire Implémenter hashCode, equals et toString INSA - ASI Persistance InfoRep : EJB 55/65 (3/11) Cycle de vie 2 2. extrait du tutoriel de SUN : http://java.sun.com/j2ee/tutorial/1_3-fcs/ doc/EJBConcepts9.html INSA - ASI Persistance InfoRep : EJB (4/11) EJB Entité Name.java package helloWorld ; i m p o r t javax . persistence .*; i m p o r t java . io . Serializable ; @ Entity @Table ( name =" names ") public c l a s s Name i m p l e m e n t s Serializable { @ Id @ Ge neratedV alue ( strategy = GenerationType . IDENTITY ) p r i v a t e i n t id ; @ Column ( unique = t r u e ) p r i v a t e String name ; p u b l i c Name () { t h i s . name = " " ; } p u b l i c Name ( String name ) { t h i s . name = name ; } p u b l i c i n t getId () { r e t u r n t h i s . id ; } p u b l i c v o i d setId ( i n t id ) { t h i s . id = id ; } p u b l i c String getName () { r e t u r n t h i s . name ; } ... 56/65 INSA - ASI Persistance InfoRep : EJB (5/11) EJB Entité Name.java ... @ Override p u b l i c b o o l e a n equals ( Object o ) { i f ( t h i s == o ) return true ; i f ( o == n u l l || getClass () != o . getClass () ) return false ; Name that = ( Name ) o ; i f ( t h i s . name != n u l l ? ! t h i s . name . equals ( that . name ) : that . name != n u l l ) return false ; return true ; } @ Override p u b l i c i n t hashCode () { r e t u r n t h i s . name != n u l l ? t h i s . name . hashCode () : 0; } @ Override p u b l i c String toString () { r e t u r n t h i s . name ; } } 57/65 INSA - ASI InfoRep : EJB Persistance 58/65 (6/11) EJB Session sans état PersistentHelloBean.java package helloWorld ; import import import import javax . ejb . Stateless ; javax . persistence .*; java . util . Collection ; java . util . Iterator ; @ Stateless public c l a s s P e r s is t e n t H e l l o Be a n i m p l e m e n t s PersistentHelloLocal , P e r s i s t e n t H e l l o R e m o t e { @ P e r s i s t e n c e Co n te xt ( unitName =" nameList ") EntityManager em ; p u b l i c String sayHello ( String s ) { String hello = " Hello " + s + " ! " ; Collection < Name > nameCollection ; em . persist (new Name ( s ) ) ; name Collection = em . createQuery ( " from Name n " ) . getResultList () ; hello += " \ nListe des personnes déjà passées : " ; f o r ( Iterator < Name > names = nameCollection . iterator () ; names . hasNext () ; ) { hello += " " + names . next () . getName () ; } r e t u r n hello ; } } INSA - ASI InfoRep : EJB Persistance (7/11) Association à une BD Tout ORM doit être associé à une BD Extérieure : Oracle, MySQL, PostgreSQL, etc. Embarquée : dans l’application J2EE (partie EJB ou web), dans le serveur d’application (H2, etc.) Interfacé par JDBC, Hibernate et JTA 59/65 INSA - ASI Persistance InfoRep : EJB 60/65 (8/11) Définition du contexte de persistance Contexte de persistance : persistence.xml < persistence version = " 1.0 " xmlns = " http :// java . sun . com / xml / ns / persistence " xmlns : xsi = " http :// www . w3 . org /2001/ XMLSchema - instance " xsi : schemaLocation = " http :// java . sun . com / xml / ns / persistence http :// java . sun . com / xml / ns / persistence / persistence_1_0 . xsd " > < persistence - unit name = " nameList " transaction - type = " JTA " > <jta - data - source > java : jboss / datasources / nameListDS </ jta - data - source > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . HSQLDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " create - drop " / > </ properties > </ persistence - unit > </ persistence > INSA - ASI InfoRep : EJB Persistance (9/11) Archive application J2EE Arborescence des répertoires persistentHello.jar |_HelloWorld | |_ PersistentHelloBean.class | |_ PersistentHelloLocal.class | |_ PersistentHelloRemote.class | |_ Name.class |_META-INF |_ persistence.xml |_ MANIFEST.MF 61/65 INSA - ASI InfoRep : EJB Persistance (10/11) JTA/H2 Utilisation (par exemple) de H2 comme BD embarquée 1 2 3 4 Création d’un utilisateur ”Admin” pour administrer JBOSS en mode console Web Création d’une ”Datasource JDBC” Activer la Datasource Déployer l’archive J2EE Exemple Name : ”nameList” JNDI : ”java :jboss/datasources/nameListDS” Driver : ”h2” Connection URL : ”jdbc :h2 :/tmp/BD” 62/65 INSA - ASI InfoRep : EJB Persistance (11/11) Côté client Client.java import import import import javax . naming . Context ; javax . naming . InitialContext ; java . util . Hashtable ; helloWorld . P e r s i s t e n t H e l l o R e m o t e ; p u b l i c c l a s s Client { p u b l i c s t a t i c v o i d main ( String [] args ) { try { Hashtable jndiProperties = new Hashtable () ; jndiProperties . put ( Context . URL_PKG_PREFIXES , " org . jboss . ejb . client . naming " ) ; Context context = new InitialContext ( jndiProperties ) ; P e r s i s t e n t H e l l o R e m o t e obj = ( P e r s i s t e n t H e l l o R e m o t e ) context . lookup ( " ejb :/ PersistentHello / P e rs i s t e n t H e ll o B e a n ! helloWorld . P e r s i s t e n t H e l l o R e m o t e " ) ; System . out . println ( obj . sayHello ( args [ args . length -1]) ) ; } c a t c h ( Exception e ) { System . out . println ( e ) ; e . pr intStackTrace () ; } } } 63/65 INSA - ASI InfoRep : EJB 64/65 Les EJB message Description 3 Classe représentant l’EJB doit implémenter l’interface javax.jms.MessageListener (donc implémenter la méthode public void onMessage(Message m)) utiliser l’annotation @MessageDriven ne pas être final 3. extrait du tutoriel de SUN : http://java.sun.com/j2ee/tutorial/1_3-fcs/ doc/EJBConcepts9.html INSA - ASI InfoRep : EJB 65/65 Références Programmation J2EE, Conteneurs J2EE, servlets, JSP et EJB : S. Allamaraju, K. Avedal, R.Browett, J. Diamond, J. Griffin, M. Holden, A. Hoskinson, R. Johson, T. Karsjens, L. Kim, A. Longshaw, T. Myers, A. Nakimovsky, D. O’Connor, S. Tyagi, G. Van Damme, G. Van Huizen, M. Wilcox, S. Zeiger Eyrolles - ISBN : 2-212-09260-1 Enterprise JavaBeans : Richard Monson-Haefel O’Reilly 3ème édition - ISBN 0-596-00226-2 JBoss 3.0 deployment and Administration Meeraj Moidoo Kunnumpurath Wrox - ISBN 1-86100-812-0