Enterprise JavaBeans

Introduction générale
Michel Buffa (buffa@unice.fr), UNSA 2002

Les promesses des EJB
Enterprise JavaBeans
Standard industriel pour un modèle de composant logiciel distribué, Permet d'implémenter des "objets métier" d'une manière propre et réutilisable, Pour le développement RAD d'applications côté serveur

Questions :
De quoi a-t-on besoin lorsqu'on développe une application distribuée orientée objet ? Qu'est-ce que les EJBs et qu'apportent-elles ? Quels sont les acteurs dans l'écosystème EJB ?

Motivation des EJBs
Considérons : un site de gestion de portefeuille boursier, une application bancaire, un centre d'appel, un système d'analyse de risque Nous parlons ici d'applications distribuées.

Choses à considérer lorsqu'on construit une application distribuée
Si on prend une application monolithique et qu'on la transforme en application distribuée, où plusieurs clients se connectent sur plusieurs serveurs qui utilisent plusieurs SGBD, quels problèmes se posent alors ?

Choses à considérer lorsqu'on construit une application distribuée
Protocoles d'accès distants (CORBA, RMI, IIOP…) Gestion de la charge, Gestion des pannes, Persistence, intégration au back-end, Gestion des transactions, Clustering, Redéploiement à chaud, Arrêt de serveurs sans interrompre l'application, Gestion des traces, règlages (tuning and auditing), Programmation multithread Problèmes de nommage Securité, performances, Gestion des états Cycle de vie des objets Gestion des ressources (Resource pooling) Requête par message (message-oriented midddleware)

Qui s'occupe de tout ceci : le middleware !
Dans le passé, la plupart des entreprises programmaient leur propre middleware.
Adressaient rarement tous les problèmes, Gros risque : ça revient cher (maintenance, développement) Orthogonal au secteur d'activité de l'entreprise (banque, commerce…)

Pourquoi ne pas acheter un produit ?
Oracle, IBM, BEA… proposent depuis plusieurs années des middleware… Aussi appelés serveurs d'application.

Serveur d'application : diviser pour règner !
Un serveur d'application fournit les services middleware les plus courants, Permettent de se focaliser sur l'application que l'on développe, sans s'occuper du reste. Le code est déployé sur le serveur d'application. Séparation des métiers et des spécificités : d'un côté la logique métier, de l'autre la logique middleware.

Serveurs d'application

Development Tools

Presentation
HTML

Business Logic
Distributed Objects Transactions

Data Access

HTML Java

Data Access Objects Enterprise Data Connectors

Content Management

Data

Java Application

Enterprise Deployment Services
Scalability Reliability Security Manageability

Encore mieux !
Il est possible d'acheter ou de réutiliser une partie de la logique métier ! Vous développez votre application à l'aide de composants.
Code qui implémente des interfaces prédéfinies. Sorte de boîte noire. Un bout de logique facilement réutilisable. Un composant n'est pas une application complète. Juste un bout. On assemble les composants comme un puzzle, afin de résoudre des problèmes importants.

Composant logiciel réutilisable
Une entreprise peut acheter un composant et l'intègrer avec des composants qu'elle a développé.
Par exemple, un composant qui sait gérer des prix. On lui passe une liste de produits et il calcule le prix total. Simple en apparence, car la gestion des prix peut devenir très complexe : remises, promotions, lots, clients privilégiés, règles complexes en fonction du pays, des taxes, etc…

Gestion des coûts sur une chaîne de production automobile.Composant logiciel réutilisable Ce composant répond à un besoin récurrent Vente en ligne de matériel informatique. Etc… Composant logiciel réutilisable . Calcul des prix des expéditions par la poste.

Composant logiciel réutilisable Composant logiciel réutilisable .

composants propriétaires uniquement. Pas de cohabitation entre composants développés pour différents serveurs d'application Dépendant d'un fabriquant une fois le choix effectué. Normalement. Développement plus rapide. Dur à avaler pour les développeurs java qui prônent la portabilité et l'ouverture ! . Naissance d'un marché des composants. IBM…) Réduction des frais de maintenance. les vendeurs de composants assurent un service de qualité (BEA. Pas encore l'explosion attendue mais… Architectures de composants Plus de 50 serveurs d'applications ont vu le jour depuis une dizaine d'années. Au début.Quel intérêt ? Moins d'expertise requise pour répondre à certains points du cahier des charges.

au VHS.Architectures de composants Nécessité de standardiser la notion de composants Ensemble de définitions d'interfaces entre le serveur d'application et les composants Ainsi n'importe quel composant peut tourner ou être recompilé sur n'importe quel serveur Un tel standard s'appelle une architecture de composants Penser aux CDs audio. à la télé. etc… Architectures de composants .

1. 3. Adopté par l'industrie.Enterprise JavaBeans (EJB) Le standard EJB est une architecture de composants pour des composants serveur écrits en java. 2. "Train once. Une spécification Un ensemble d'interfaces Pourquoi java ? EJB = uniquement en java Séparation entre l'implémentation et l'interface Robuste et sûr : mécanismes + riche API + spécificité du langage (reflexivité. 2.NET CORBA : mais nombreux serveurs EJB basés sur CORBA) . code anywhere" Portable facilement Rapid Application Development (RAD) EJB signifie deux choses : 1. introspection. chargement dynamique) Portable Autre possibilités Composants Microsoft .

etc…) Exemple : DELL attaque le serveur d'INTEL directement à travers un protocole XML pour réserver des pièces. SAP R/3. envoyer un mail de confirmation après une commande. etc…) Applications web : intégration avec JSP/Servlets Web services basés sur XML (SOAP. UDDI. etc… Accèder à un SGBD Accèder à un autre système d'information (CICS. COBOL. EJB ne fournit pas de GUI GUI = côté client Applications classiques Servlets/JSP .EJB pour développer des composants business Implémenter de la logique métier : calcul des taxes sur un ensemble d'achats.

flashline.com ou www. six métiers sont impliqués 1 . en UML et en développement Java.com pour voir une liste) L'écosystème EJB 2 . d'une équipe de développeurs/concepteurs maison… .Le fournisseur d'EJBs Peut-être un membre de votre équipe. d'un consultant. c'est un expert en Génie Logiciel.componentsource.L'assembleur d'application Il s'agit de l'architecte de l'application Il est client des EJBs achetées ou développées Il décide de la combinaison de composants dont il a besoin Fournit un GUI à l'application Conçoit et développe de nouveau composants Conçoit et développe les programmes clients Définit le mapping avec les données manipulées par les différents composants En général.L'écosystème EJB Pour déployer et exécuter un projet à base d'EJBs. ou bien une entreprise qui vend des EJBs (www. Il peut s'agir d'un intégrateur de systèmes.

com ou www.hostJ2EE. .L'écosystème EJB 3 .loudcloud.Le déployeur d'EJBs Après que l'application ait été assemblée.L'administrateur système Vérifie le bon fonctionnement de l'application en exploitation. optimisation des performances… Il adapte les composants et le serveur à l'application Il peut être une équipe ou une personne. etc…) sur le serveur d'applications. Exemples aux USA : www. etc…) Branchement de services annexes (LDAP. Lotus Notes. Computer Associates. arrêt) du système. Choix du hardware. Certains serveurs d'application savent téléphoner et appeler l'administrateur système en cas de problème. Ponts avec les outils de Tivoli. Il effectue la maintenance hardware et software (lancement. des SGBD. elle doit être déployée sur un ou plusieurs serveurs d'application Attention à la sécurité (firewall. etc… Paramétrage du serveur d'application. Microsoft Active Directory. un consultant ou un vendeur d'hébergement de serveurs d'applications.com L'écosystème EJB 4 . Il utilise les outils de monitoring des serveurs d'application. … via JMX.

JBoss… Il existe d'autre containers spécialisés (container Web comme Tomcat. Rational Rose Outil de test (JUnit). construire. etc… Principaux IDEs : JBuilder. de stress (LodeRunner). déployer les EJBs est standard.Le fournisseur du serveur d'application et des containers EJB container = environnement au sein du serveur dans lequel les EJB vivent. BES. Exemples : Weblogic. Oracle Orion Server. L'écosystème EJB 6 . Visual Cafe. Pourtant la manière de développer. maintenir. JRun. Visual Age. Websphere.L'écosystème EJB 5 . On confond en général container et serveur d'application.Les vendeurs d'outils Développer une application à base d'EJB est assez lourd. Le container EJB fournit les services middleware et manage les EJBs. Autres outils : les outils UML comme Together/J. Resin…) Le fournisseur du serveur d'application est le même que le fournisseur de containers EJB. etc… . Il est très pratique d'utiliser un IDE pour simplifier les tâches répétitives comme le déploiement.

Mapping BD relationnelles/Objets Mapping BD objet/Objets Etc… Pas encore standardisé dans la spécification EJB 2.0 .Les différents métiers… Les différents métiers… Bientôt un nouveau métier : le "persistence manager" Développe des outils qui se "branchent" sur le serveur d'application et implémentent les mécanismes de persistance.

La plate-forme Java J2EE EJB = la clé de voûte d'une architecture distribuée java appelée J2EE Pour le développement d'application serveur Ensemble de spécifications et d'APIs Contient deux autres architectures 1. La plate-forme Java J2EE Chaque API dans J2EE à sa propre spécification (PDF) Batterie de logiciel pour valider les implémentations (test suites) Implémentation de référence J2EE est livrée avec un serveur d'application par exemple… Ensemble de "blueprints" : définit précisément le rôle de chaque API (PDF) . J2SE : pour applications et applets standards Non attaché à un vendeur particulier. J2ME (Java 2 Micro Edition) : pour les mobiles 2. Quiconque respecte les spécification est "J2EE compliant" Applications développées indépendantes des vendeurs d'outils.

J2EE : les APIs J2EE comprend en plus de J2ME et J2SE EJB : standard de définition de composants Java 2 RMI et RMI-IIOP : objets distribués JNDI (Java Naming and Directory Interface) JDBC (Java Data Base Connectivity) JTA (Java Transaction API) JMS (Java Messaging Service) Java Servlets and Java Pages (JSP) Java IDL (Corba) JavaMail JCA (J2EE Connector Architecture) : ponts vers SAP/3. CICS… JAXP (Java API for XML Parsing) JAAS (Java Authentification and Authorization Service) J2EE .

Integrated Architecture Development and Deployment Tools Presentation Servlets/JSP HTML Visual Servlets On Demand Java Business Logic EJB Triggers Content Management Data Access JDBC 2.0 Distributed Data Cache Data Access Objects Enterprise Data Connectors Data Java Application JTS/JTA JNDI JavaMail RMI-IIOP JMS Enterprise Deployment Services Scalability Reliability Security Manageability Consistent.0 Distributed Data Cache Data Access Objects Enterprise Data Connectors Data Java Application JTS/JTA JNDI JavaMail RMI-IIOP JMS Enterprise Deployment Services Scalability Reliability Security Manageability .J2EE for the Real World Development and Deployment Tools Presentation Servlets/JSP HTML Visual Servlets On Demand Java Business Logic EJB Triggers Content Management Data Access JDBC 2.

suivent la spécification EJB Cette spécification requiert que le Bean expose certaines méthodes . UNSA 2002 Enterprise Bean Composant serveur qui peut être déployé Composé de un ou plusieurs objets Les clients d'un Bean lui parlent au travers d'une interface Cette interface. de même que le Bean.EJB : les fondamentaux Michel Buffa (buffa@unice.fr).

extensible… 3 types de Beans : Session Bean Session Beans Modèlisent un traitement (business process) Correspondent à des verbes. affichage de catalogue de produit. etc… Modèle flexible. des accès à une base de données. gestionnaire de prix… Les actions impliquent des calculs. de commandes. vérifieur de données bancaires.Enterprise Bean Le client d'un Bean peut être Une servlet Une applet Une application classique Un autre Bean On peut décomposer une application en un graphe de tâches/sous-tâches Exemple : achat d'un CD à partir du code-barre Scanner (qui a une JVM embarquée) client d'un Bean sur le Serveur Ce Bean client d'autres Beans : gestion de catalogue. de gestion de transaction VISA. à des actions Ex : gestion de compte bancaire. etc.) Souvent clients d'autres Beans . consulter un service externe (appel téléphonique.

Produit Commande. ligne de commande . un Bean compte bancaire.0 Exemple de Session/Entity bean Session Bean Gestion de compte Vérificateur de CB Entity Bean Compte bancaire Carte de crédit Système d'entrée gestion Commande. ligne de de commandes commande Gestion de catalogue Gestionnaire d'enchères Gestion d'achats Produits Enchère.3 types de Beans : Entity Bean Entity beans Modèlisent des données Correspondent à des noms Ce sont des objets java qui cachent des données d'une base de données Ce sont des objets persistants Ex : un Bean Personne. Serveurs pour des Beans Session le plus souvent Servent de proxy entre la logique métier et les base de données Mapping base de donnée relationnelle/Objet facilité par EJB 2. un Bean commande. un Bean produit. Produit.

On les invoque en leur envoyant des messages. .3 types de Beans : Message-Driven Bean Message-Driven Beans Nouveau dans EJB 2. des autorisations d'achat par CB. Risque de mauvaise utilisation mais… On est gagnant sur le long terme. Ex : message pour déclencher des transactions boursières. Similaire aux Session bean : représentent des verbes ou des actions. Standard EJB plus difficile à apprendre. Souvent clients d'autres beans… 3 types de Beans : pourquoi ? Pas d'Entity Beans dans les solutions Microsoft par exemple… Nombreuses compagnies impliquées dans les standards EJB/J2EE Leurs clients ont des besoins variés. Solution proposée flexible mais plus complexe.0.

Clients interagissant avec un serveur à base d'EJBs Les objets distribués au cœur des EJBs .

2.Les objets distribués et le middleware Lorsqu'une application devient importante.etc… C'est là qu'intervient le middleware! Deux approches 1. Middleware implicite Middleware explicite . Middleware explicite. des besoins récurrents apparaissent : sécurité. transactions.

Compte c2. Appeler l'API de transaction pour terminer la transaction. Difficile à maintenir. 5. Appel vers l'API middleware qui fait une vérification de sécurité. long montant) 1. Votre code est dépendant des API du vendeur de middleware que vous utilisez.Middleware explicite Exemple : transfert d'un compte bancaire vers un autre : transfert(Compte c1. 2. 4. 6. Middleware explicite Difficile à écrire. Faire le calcul : enlever de l'argent d'un compte pour le mettre dans l'autre Appeler l'API pour mettre à jour les lignes dans les tables. 3. . Appel vers l'API de transaction pour démarrer une transaction. Appel vers l'API pour lire des lignes dans des tables d'une BD.

par exemple comment changer le nom d'un client. etc… Entity Bean : logique orientée donnée. diminuer un compte bancaire… Message-Driven Bean : logique orientée message. saisie de commandes. transfert de compte bancaire.Middleware implicite Constitution d'un EJB : Enterprise Bean class La classe du Bean (Enterprise Bean class) Une classe qui implémente une interface précise et qui respecte certaines règles. Il s'agit de l'implémentation du bean lui-même. calculs. traitement après réception d'un ordre d'achat d'actions boursières… . Session Bean : logique métier.

afin d'assurer le traitement middleware implicite. le container appelle les méthodes de la classe du Bean Le développeur de composant se concentre sur la logique.SessionBean Javax.Constitution d'un EJB : Enterprise Bean class Interfaces implémentées par la classe du Bean Tous les beans implémentent javax.ejb.EntityBean Javax. Une fois ce traitement effectué.ejb. ignore la partie middleware.ejb. Important : cette interface dérive de Serializable Chaque type de bean implémente des interfaces plus spécifiques : Javax. .ejb.EnterpriseBean : juste un marqueur.MessageDrivenBean Constitution d'un EJB : EJB Object Les clients n'invoquent jamais directement les méthodes de la classe du Bean Les appels de méthodes (requests) sont interceptés par le Container.

Monitoring : statistiques. pooling des instances (mémoire). Sécurité : le client est-il autorisé ? Gestion des ressources + cycle de vie des composants : threads. sockets. graphiques temps réel du comportement du système… … Constitution d'un EJB : EJB Object Container = couche d'indirection entre le client et le bean Cette couche est matérialisée par un objet unique : l'EJB Object . Persistance. Threading des clients en attente.Constitution d'un EJB : EJB Object Que se passe-t-il lors de l'interception ? Prise en compte des transactions. Clustering. connexions DB. Accès distant aux objets.

gestion des ressources. • Fournit les services au container EJB Container EJ Bean EJ Bean Serveur EJB . Accès Distant.Constitution d'un EJB : EJB Object L'EJB Object contient du code spécifique au container (vendeur-dépendant) Il appelle les méthode de la classe du Bean. Persistance. etc. Securité. EJB : classe du Bean et EJB Object EJ Bean EJ Bean • Code simple EJB Server • Génération du code à partir du Bean Container EJB • Le code généré fournit Transactions. Il est généré par le container ! Chaque container est livré avec des outils pour générer les EJB Object pour chaque Bean.

etc…) Serveur EJB Container EJB EJ Bean EJ Bean Code généré Constitution d'un EJB : l'interface distante Les clients invoquent les méthodes des EJB Objects. mappings objets/BD relationelle. l'interface distante .EJB Object : génération du code • Utilisation du descripteur de déploiement (fourni par l'auteur du Bean) Container EJB EJ Bean EJ Bean • Paramètres de déploiement = securité.) • Génération du code pour intégrer le bean dans le container. etc. ajout du ‘plumbing’ (persistance. Ces EJB Objects doivent cloner toutes les méthodes que le bean expose. Comment l'outil qui génère l'EJB Object peut-il connaître la liste des méthodes à cloner ? Réponse : il utilise une interface fournie par le programmeur du bean. securité.

public abstract javax. Qui implémentera cette interface ? L'EJB Object généré par le container ! Presque rien à faire pour le développeur de bean ! .RemoteException. public abstract boolean isIdentical(javax.rmi. } Constitution d'un EJB : l'interface distante Le programmeur du Bean dérivera son interface distante de javax.RemoteException.Remote { public abstract javax.ejb.RemoveException.Constitution d'un EJB : l'interface distante public interface javax.ejb.Object getPrimaryKey() throws java.rmi.rmi.ejb.ejb. Rajoutera les signatures des méthodes qu'il souhaite exposer.RemoteException.ejb.lang. public abstract void remove() throws java.rmi.EJBObject) throws java.RemoteException.RemoteException.rmi.Handle getHandle() throws java.EJBHome getEJBHome() throws java.EJBObject extends java.rmi.EJBObject. javax. public abstract java.ejb.

entre autres… Constitution d'un EJB : Home Object Nous avons vu comment les clients appelaient les méthodes d'un Bean : via l'EJB Object. Quiconque implémente Remote est appelable à distance depuis une autre JVM. EJB Objects = RMI-IIOP + EJB compatibles RMI-IIOP = convention de passage de paramètres + valeurs de retour lors d'appels de méthode distante.Remote.rmi.Java RMI-IIOP et EJB Objects Javax.ejb.EJBObject dérive de java. Mais comment obtiennent-ils une référence sur l'EJB Object ? En effet : pas d'instanciations lorsque on travaille avec des objets distants ! Solution : le client demande la référence à une fabrique d'EJB Objects (EJB Object Factory) Design pattern! .

Responsabilités du Home Object Créer les EJB Objects.Constitution d'un EJB : Home Object L'EJB factory est responsable de l'instanciation et de la destruction des EJB Objects. La spécification EJB appelle cette factory un Home Object. Constitution d'un EJB : Home Object Comme les EJB Objects. Trouver les EJB Objects existants (Entity beans seulement) Supprimer les EJB Objects. les Home Objects sont générés par le container Contiennent du code spécifique. etc… . Assurent le load-balancing.

détruire et localiser les EJB Objects Le Home Object (généré par le container) implémente cette interface.rmi.EJBHome dérive de java. le développeur du bean doit spécifier une interface Home Constitution d'un EJB : l'interface Home L'interface Home définit Les méthodes pour créer. Comme pour les EJB Objects. on demande au Home object de retourner une référence.EJBHome Javax.ejb. L'interface fournie par le développeur dérive de javax. Comme pour les constructeurs. il est possible de passer des paramètres d'initialisation.ejb.Remote Les Home objects sont aussi des objets distants.Constitution d'un EJB : l'interface Home Comment un Home object sait de quelle manière le client veut initialiser l'EJB Object ? Rappel : au lieu d'appeler un constructeur. compatibles RMI-IIOP .

RemoteException.HomeHandle getHomeHandle() throws java. public void remove(Object primaryKey) throws java. } Constitution d'un EJB : les interfaces locales Problème : la création de bean et l'appel de méthode distante coûtent cher ! .ejb. public void remove(Handle handle) throws java.rmi. public javax.rmi.RemoveException.ejb.rmi.RemoteException javax.ejb.rmi.RemoveException. javax.Constitution d'un EJB : l'interface Home public interface javax.Remote { public EJBMetaData getEJBMetaData() throws java.ejb.RemoteException.rmi.RemoteException.EJBHome extends java.

Introduit la notion de Local Object. puis au client . 5.Constitution d'un EJB : les interfaces locales Commentaires sur la figure précédente 1. 7. 3. 6. 8. en remplacement de EJB Object Les Local Objects implémentent une interface locale au lieu d'une interface distante Exemple d'appel de méthode distante 1. 9. Le Bean fait son travail. L'EJB Object effectue les appels middleware. On fait le chemin inverse pour retourner la valeur de retour vers le client ! …Sans compter le chargement dynamique des classes nécessaires ! Constitution d'un EJB : les interfaces locales Nouveau dans EJB 2. Le stub encode les paramètres dans un format capable de voyager sur le réseau. Le client appelle le Local Object. L'EJB Object appelle la méthode du bean. 4. 3. Le Local Object appelle le middleware puis la méthode du bean La valeur de retour est renvoyée au Local Object. Le stub ouvre une connexion sur le skeleton (squelette). 2. Le skeleton décode les paramètres. Le client appelle un stub (souche). 2.0 : les interfaces locales. Le skeleton appelle l'EJB Object. 10.

le développeur peut fournir une interface locale.1) ou on a interface distante implémentée par EJB Object Pour la création/localisation de beans. qui sera implémentée par le container en tant que Local Object A distinguer du cas "normal" (EJB 1.Constitution d'un EJB : les interfaces locales Pour l'appel distant de méthodes. paramètres et valeurs de retour (lors des appels de méthodes) se passent maintenant par référence Toujours par valeur dans le cas d'appels distants! Plus performant mais sémantique différente. Attention. Difficile de passer d'une implémentation locale à une implémentation classique Aurait pu être fait dans les descripteurs (weblogic) . qui sera implémentée par le container en tant que Home Object local A comparer avec Home Interface implémentée par le container en tant que Home Object Constitution d'un EJB : les interfaces locales Les interfaces locales ne tournent que si les EJB sont dans le même processus (même container). le développeur peut fournir une interface home interface locale.

Attention si on les écrit à la main! Outils d'aide au déploiement : IDEs (Jbuilder. Constitution d'un EJB : les descripteurs de déploiement Descripteurs spécifiques au serveur d'application Chaque vendeur ajoute des trucs en plus : loadbalancing. A l'extérieur de l'implémentation du bean. outils spécifiques (Borland Application Server. Weblogic 6.1) Descripteurs peuvent être modifiés après le déploiement. persistance complexe.xml avec Borland) . clustering. monitoring… Dans des fichiers spécifiques (inprise-ejb. on utilise un descripteur de déploiement (XML) Standardisé.Constitution d'un EJB : les descripteurs de déploiement Pour informer le container des besoins middleware. Visual Cafe).

jar Résumé Enterprise Bean class Interface distante (remote interface)/Interface locale EJB Object/Local Object Home interface/Local Home interface Home Object/Local Home Object Descripteur de déploiement standard Descripteurs spécifiques au vendeur Fichier .Déploiement : un fichier .jar de l'EJB .

5. vérifier la config. Ecrire les fichiers . sinon.Ecriture d'un premier Bean Hello World ! Comme c'est original ! Michel Buffa (buffa@unice. 3. 6.jar contenant les . Compiler les . 7. UNSA 2002 Comment s'y prendre ? Ordre typique des opérations 1.class et le descripteur. Créer un . Ecrire le descripteur du bean. compiler. 2. . Ecrire. Deployer le .jar (via outil ou simple copie).java de l'étape 1. 4. exécuter un client de test du bean.java qui composent le bean. Vérifier que le serveur fonctionne et a bien déployé le bean.fr).

} .* * This interface is what clients operate on when * they interact with EJB objects. /** * This is the HelloBean remote interface. the * implemented object is the EJB object. */ public interface Hello extends javax.RemoteException.rmi.returns a greeting to the client. which * delegates invocations to the actual bean.Modèle objet du bean HelloWorld L'interface distante package examples. The container * vendor will implement this interface.ejb.hello . */ public String hello() throws java.EJBObject { /** * The one method .

/** * This is the HelloBean local interface. javax.EJBLocalObject { /** * The one method . which * corresponds to the ejbCreate() method in HelloBean.ejb. */ public String hello().ejb. which delegates invocations * to the actual bean.the * implemented object is called the Home Object.hello . */ Hello create() throws java. and serves * as a factory for EJB Objects. * * One create() method is in this Home Interface. the implemented object is the * EJB local object.RemoteException. * The container vendor will implement this * interface. This interface * is implemented by the EJB Server's tools . /** * This is the home interface for HelloBean.ejb.L'interface locale package examples. */ public interface HelloHome extends javax.CreateException. */ public interface HelloLocal extends javax.returns a greeting to the client.EJBHome { /* * This method creates the EJB Object. } .rmi. } L'interface Home package examples. * * @return The newly created EJB Object. * * This interface is what local clients operate * on when they interact with EJB local objects.

println("ejbPassivate()"). /** * This is the local home interface for HelloBean.println("hello()"). } public void ejbActivate() { System. // // EJB-required methods // public void ejbCreate() { System. } } } public void setSessionContext(javax. return "Hello.ejb.out.println("ejbRemove()").out. World!". */ public class HelloBean implements javax.CreateException. } La classe du bean package examples.L'interface Home locale package examples.println("ejbCreate()").EJBLocalHome { /* * This method creates the EJB Object. * This interface is implemented by the EJB Server's * tools .out.ejb. and serves as a factory for * EJB local objects. } public void ejbPassivate() { System. .the implemented object is called the * local home object.println("ejbActivate()").ejb.SessionContext ctx) { this.out. */ public interface HelloLocalHome extends javax. /** * Demonstration stateless session bean.SessionBean { private SessionContext ctx.ctx = ctx. */ HelloLocal create() throws javax.ejb. * * @return The newly created EJB Object. } public void ejbRemove() { System. } // // Business methods // public String hello() { System.out.

Un contexte par type de Bean SessionContext. ejbActivate() et ejbPassivate() n'ont pas d'utilité dans le cas de session bean stateless Elles sont vides. Etudiées plus tard. setMessageDrivenBeanContext() . Les EJBContexts : le lien avec le container Sert à encapsuler le domaine dans lequel évolue le bean dans un objet. MesageDrivenContext Méthodes correspondantes setSessionContext(). setSessionContext() appelé par le container. setEntityContext().La classe du bean ejbCreate() correspond au create() de l'interface Home Une seule méthode métier : hello() On la retrouve dans les interfaces distante et locales. EntityContext.

ejb.Les EJBContexts : le lien avec le container Tous les contextes implémentent public interface javax. public javax.lang.security. * * You can use them to create. */ public javax.UserTransaction getUserTransaction().transaction. } . public java.ejb..see Chapter X */ public boolean isCallerInRole(java.EJBContext { /* * Call these from within your bean to access * your own home object or local home object. /* * These are security methods .Principal getCallerPrincipal(). /* * These are transaction methods .. public void setRollbackOnly().EJBLocalHome getEJBLocalHome(). public javax. . destroy.EJBHome getEJBHome(). or * find EJB objects and EJB local objects * of your own bean class type. Les EJBContexts : le lien avec le container .see Chapter X */ public boolean getRollbackOnly().String).ejb.

HelloLocal</local> <ejb-class>examples. Inc.HelloHome</home> <remote>examples.//DTD Enterprise JavaBeans 2.dtd"> <ejb-jar> <enterprise-beans> <session> <ejb-name>Hello</ejb-name> <home>examples.sun.Les EJBContexts : le lien avec le container Le descripteur de déploiement <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems.Hello</remote> <local-home>examples.HelloLocalHome</local-home> <local>examples.com/j2ee/dtds/ejb-jar_2_0.0//EN" "http://java.HelloBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> </ejb-jar> .

jar de l'EJB Il faut mettre tous les fichiers compilés + descripteurs dans un .jar Depuis un IDE ou à la main jar cf HelloWorld.class examples/HelloHome. spécifique.MF META-INF/ejb-jar.class .class examples/HelloLocal.Le descripteur de déploiement spécifique Selon les serveurs d'application. Voir pendant les exercices… Le fichier .class examples/HelloLocalHome.jar META-INF/MANIFEST.class examples/Hello. il peut y avoir un descripteur en plus.jar * Contenu de HelloWorld.xml examples/HelloBean.

Localiser (lookup) un objet Home.jar. Le container génère les stubs et skeletons pour les appels RMI-IIOP. A l'aide d'un outil de déploiement spécifique (BAS…) Lors du déploiement Vérification du fichier. Vérifier le déploiement Le serveur doit vous avertir qu'il a bien chargé le bean. Utiliser cet objet Home pour créer (create) un EJBObject. Clients CORBA : par exemple écrits en C++… Ils utilisent COS Naming Service et Object Transaction Service (OTS) pour les transactions… Quel que soit le client 1. 2.Déployer le bean Cette étape varie selon le container Simple copie avec JBoss. Clients JAVA RMI-IIOP : ils utilisent JNDI pour localiser les objets et Java Transaction API pour contrôler les transactions. 4. 2. . Appeler les méthodes de l'EJBObject. Écriture d'un client Deux types de clients 1. Supprimer (remove) l'EJBObject. 3. Le container génère les EJBObjects et EJBHome.

EJB. imprimantes. Datasource (base de données)… JNDI est un pont vers des services tels que LDAP.Client : localiser (lookup) un objet Home. services. iPlanet Directory Server… JNDI permet de rendre transparente la localisation des objets… Client : les étapes en images . On ne sait pas où se trouve l'objet… Utilisation de JNDI JNDI sert à mapper des ressources sur des noms logiques : utilisateurs. Microsoft Active Directory. Lotus Notes Domino Server.

InitialContext.narrow(obj. etc * by passing in the environment properties.Properties. */ public class HelloClient { public static void main(String[] args) throws Exception { /* Setup properties for JNDI initialization. */ Properties props = System.class).PortableRemoteObject.println(hello. * The initial context is a starting point for * connecting to a JNDI tree.the * factory for Hello EJB Objects */ Object obj = ctx.getProperties(). */ hello. We choose our JNDI * driver. /* Obtain the JNDI initial context.hello()). /* Done with EJB Object. import java. * These properties will be read-in from * the command-line. the network location of the server. } } The * EJB object will delegate the call to the bean.Client : le code package examples.naming.. so remove it. HelloHome. import javax.Context. /* Home objects are RMI-IIOP objects. import javax. /* Use the factory to create the Hello EJB Object */ Hello hello = home.rmi. * See Appendix X for more details on this. * We then print the result to the screen. */ HelloHome home = (HelloHome) javax.out. Client : le code . /* Call the hello() method on the EJB object. * The container will destroy the EJB object. and so * they must be cast into RMI-IIOP objects * using a special RMI-IIOP cast. * receive the result..remove().naming. */ Context ctx = new InitialContext(props). /* Get a reference to the home object .create(). */ System. .. /** * This class is an example of client code which invokes * methods on a simple stateless session bean. .util. and return it to us.lookup("HelloHome").

fr). UNSA 2002 .Exécution du client de test Place aux exercices !!!! Tiens. une question : que représente le mot-clé this pour un EJB ? Introduction aux Session Beans Michel Buffa (buffa@unice.

Il peut le détruire lorsque le client se déconnecte. Transactions bancaires… Durée de vie d'un Session Bean Durée de vie = la session En gros. Le contraire des Entity Beans que nous verrons plus tard. Dans une logique e-commerce. le temps qu'un utilisateur est connecté sur le site. d'un catalogue de produits. Les Session Beans ne résistent pas à des crashes du serveur. Le container crée une instance lorsqu'un client se connecte sur le Session Bean.Session Bean : rappel Un Session Bean représente une action. Compression vidéo. un algorithme. Gestion d'un caddy. une logique métier. un verbe. Ce sont des objets en mémoire. le temps qu'un client reste connecté sur le bean. non persistants. Un enchaînement de tâches… Exemples Saisie d'une commande. .

) Autre exemple : une application bancaire. il faut un moyen de conserver un état (le caddy par ex. 2. On en va pas à chaque fois lui redemander son No de compte… . Stateful Session Beans. Chacun modélisant un type particulier de conversation. Exemple : un client surfe sur un site de ecommerce. Stateful Session Beans Certaines conversations se déroulent sous forment de requêtes succesives. Conversation = suites d'appels de méthodes. Le client effectue plusieurs opérations. sélectionne des produits. Il existe deux types de Session Beans 1.Types de Session Beans Chaque EJB a un moment donné entretient une conversation avec un client. Stateless Session Beans. remplit son caddy… D'une requête HTTP à l'autre.

Stateless Session Beans Certaines conversations peuvent se résumer à un appel de méthode. simple calcul (validation de No de CB).Stateful Session Beans En résumé. compression… Le client passe toutes les données nécessaires au traitement lors de l'appel de méthode. Avec certains containers. Une instance de Stateless Session Bean n'est pas propre à un client donné. . les Stateful Session Beans peuvent être persistants (BAS/BES…) par sérialisation. Le container est responsable de la création et de la destruction du Bean Il peut le détruire juste après un appel de méthode. Si un appel de méthode change l'état du Bean. ou le garder en mémoire pendant un certain temps pour réutilisation. lors d'un autre appel de méthode l'état sera disponible. un Stateful Session Bean est utile pour maintenir un état pendant la durée de vie du client au cours d'appels de méthodes successifs. Conséquence : une instance de Stateful Session Bean par client. elle peut être partagée entre chaque appel de méthode. Au cours de transactions successives. sans besoin de connaître l'état courant du Bean Ex : simple traitement.

Pooling de Stateless Session Beans Pooling des Stateful Session Beans Le pooling des instances de Stateful Session Beans n'est pas aussi simple… Le client entretient une conversation avec le bean. dont l'état doit être disponible lorsque ce même client appelle une autre méthode. sockets…) Mauvaise scalabilité du système. Problème si trop de clients utilisent ce type de Bean en même temps. L'état peut occuper pas mal de mémoire… Problème similaire à la gestion des tâches dans un OS… . Ressources limitées (connexions. mémoire.

sockets. Lorsqu'on a de nouveau besoin de ce processus. Etc… . peuvent être utilisées par un autre client. Ceci arrive souvent lorsqu'on passe d'une application à l'autre… Pooling des Stateful Session Beans Avec les Stateful Session Beans on fait pareil ! Entre chaque appel de méthode. Un utilisateur d'un site de e-commerce lit les infos sur la page www. on swappe son état mémoire sur disque dur.Pooling des Stateful Session Beans Avec un OS : on utilise le concept de mémoire virtuelle… Lorsqu'un processus ne fait plus rien (Idle). libérant de la place. la mémoire intrinsèque qu'il occupe. réfléchit… de temps en temps il clique sur un bouton… Pendant qu'il ne fait rien. un client ne fait rien (Idle). on fait l'inverse. l'état du bean est swappé mais les ressources telles que les connexions BD.

Pooling des Stateful Session Beans Ceci a un coût : l'activation/passivation génère des E/S Choix du bean à swapper par LRU le plus souvent (Least Recent Used) Choix du bean à activer : lorsqu'on le demande (just in time) En quoi consiste l'état d'un Bean Stateful? L'état conversationnel d'un bean suit les règles de la sérialisation d'objets en java.EnterpriseBean implémente java.Serializable Tous les attributs du Bean non transcients sont donc concernés. En effet. .io. Rappelez-vous que javax.ejb. la passivation (swap de la mémoire vers le HD) et l'activation (l'inverse) sont réalisées par sérialisation.

EJBContext. EJBHome.En quoi consiste l'état d'un Bean Stateful? Sont concernées également tous les attributs issus du container Références vers EJBObject. contextes JNDI… Passivation d'un Stateful Session Bean .

le container l'avertit en appelant sa méthode ejbPassivate() Il peut libérer des ressources (connexions…) Idem lorsque le bean vient d'être activé. le container appelle ejbActivate() .Activation d'un Stateful Session Bean Activation/Passivation callbacks Lorsqu'un bean va être mis en passivation.

rmi. /** * Demonstration Stateful Session Bean. * * This example shows the basics of how to write a stateful * session bean. */ public class CountBean implements SessionBean { // The current counter is our conversational state. /** * These are CountBean ’s business logic methods.and has a business method which * increments the value.which delegates invocations to the * actual bean.Count : l'interface distante package examples.ejb. */ public interface Count extends EJBObject { /** * Increments the int stored as conversational state */ public int count()throws RemoteException.The container vendor will * implement this interface.*.ejb. import java.and how passivation/activation works. import javax.This Bean is initialized * to some integer value. import javax. public int val.the implemented object is * the EJB object. } CountBean : la classe du bean package examples.RemoteException. * * This interface is what clients operate on when they * interact with EJB objects.*. // //Business methods // .

println("count()"). public javax.out.out. remplace le this pour les EJB ! .val =val.CountBean : la classe du bean /** Counts up */ public int count(){ System.EJBObject getEJBObject(). } public void setSessionContext(SessionContext ctx){ } } CountBean : la classe du bean Val est serializable.println("ejbActivate()"). } Ces deux méthodes permettent de récupérer une référence sur l'EJBObject associé au Bean.ejb. représente l'état du bean Le bean est stateful mais ce n'est précisé nulle part dans le code. setSessionContext(SessionContext) Appelé par le container. L'objet SessionContext implémente public interface javax.SessionContext extends javax. } public void ejbActivate(){ System.println("ejbRemove()").out.EJBLocalObject getEJBLocalObject().println("ejbCreate()"). } public void ejbPassivate(){ System. } // // EJB-required methods // public void ejbCreate(int val)throws CreateException { this. return ++val. System.ejb.out. } public void ejbRemove(){ System.EJBContext { public javax.println("ejbPassivate()").ejb.ejb.out.

This interface * is implemented by the EJB Server’s glue-code tools .RemoteException.CountBean</ejb-class> <session-type>Stateful</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> </ejb-jar> . * * One create() method is in this Home Interface. */ public interface CountHome extends EJBHome { /* * This method creates the EJB Object.CountHome</home> <remote>examples. which * corresponds to the ejbCreate() method in the CountBean file.Count</remote> <ejb-class>examples.0//EN" "http://java. Inc.CountHome : l'interface Home package examples. /** * This is the home interface for CountBean.dtd"> <ejb-jar> <enterprise-beans> <session> <ejb-name>Count</ejb-name> <home>examples.sun. import java. */ Count create(int val) throws RemoteException.the * implemented object is called the Home Object. CreateException.com/dtd/ejb-jar_2_0. import javax.ejb.xml : descripteur de déploiement <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems.//DTD Enterprise JavaBeans 2. } ejb-jar.rmi. * @param val Value to initialize counter to * @return The newly created EJB Object. and serves * as a factory for EJB Objects.*.

/** This class is a simple example of client code. Si on crée trois Beans. * We create 3 EJB Objects in this example. à swapper l'état d'une instance lors des requêtes… Client de l'EJB package examples. CountHome home = (CountHome) javax.*.lookup("CountHome").ejb. /* Get a reference to the Home Object .naming.class).Descripteur de déploiement propriétaire Rien de spécial à signaler… Truc intéressant à faire : indiquer au container que l'on ne désire pas plus de deux instances de l'EJB dans le pool. import java. ça va obliger le container à mettre en œuvre le pooling.getProperties(). import javax. CountHome.PortableRemoteObject.rmi.util. */ public class CountClient { public static void main(String[] args) { try { /* Get System properties for JNDI initialization */ Properties props = System.narrow( ctx. . import javax. but we only allow * the container to have 2 in memory.Properties. This illustrates how * beans are passivated to storage.the * factory for EJB Objects */ Context ctx = new InitialContext(props).*.

. i++) { /* Add 1 and print */ countVal = count[i].count(). Client de l'EJB /* Let’s call count() on each EJB Object to * make sure the beans were passivated and * activated properly.Client de l'EJB /* An array to hold 3 Count EJB Objects */ Count count[] = new Count[3].sleep(500).out. i < 3.println("Instantiating beans . } // try . } // try } // main } .out. } // for /* Done with EJB Objects.out. i++) { count[i].create(countVal).. int countVal = 0. System.. } } catch (Exception e) { e.sleep(500). for (int i=0. /* Add 1 and print */ countVal = count[i].out.printStackTrace(). . /* Create and count() on each member of array */ System.println(countVal). /* Sleep for 1/2 second */ Thread.remove().println(countVal). /* Sleep for 1/2 second */ Thread. */ System. so remove them */ for (int i=0.println("Calling count() on beans .count(). i < 3. . . "). "). System. i++) { /* Create an EJB Object and initialize it * to the current count value */ count[i] = home. for (int i=0. i < 3.

. count() ejbPassivate() ejbActivate() count() ejbPassivate() ejbActivate() ejbRemove() ejbActivate() ejbRemove() ejbRemove() Cycle de vie d'un Session Bean stateless . .. 2 3 4 Sortie serveur ejbCreate() count() ejbCreate() count() ejbCreate() ejbPassivate() count() ejbPassivate() ejbActivate() count() ejbPassivate() ejbActivate() count() ejbPassivate() ejbActivate() .Exécution du client. .. .n Sortie client Instantiating beans . 1 2 3 Calling count() on beans . déploiement du Bea.

UNSA 2002 .Cycle de vie d'un Session Bean stateful Introduction aux Entity Beans Michel Buffa (buffa@unice.fr).

introducton Un Entity Bean représente Des objets persistants stockés dans une base de donnée. Les caractéristiques des entity beans. etc… A partir d'un état sérialisé. Les concepts de programmation des entity beans. il faut sauvegarder aussi les attributs de ces instances. des méthodes de java. Rappel : l'état d'un objet peut être quelque chose de très compliqué.Entity Bean. au travers de l'interface java.Serializable.io.ObjectInputStream et java. y compris les atributs hérités. Etat d'un objet = ses attributs. Des noms. du point de vue du programmeur. Ce qu'est un entity bean. on peut reconstruire l'objet En java. La persistance par sérialisation Sérialisation = sauvegarde de l'état d'un objet sous forme d'octets.io.io. Si les attributs sont eux-même des instances d'une classe.ObjectOutputStream . des données Dans ce chapitre on étudiera Le concept de persistance.

on associe cette classe à une table qui possède deux colonnes : nom et prenom. Comment retrouver ceux qui ont un solde négatif ? Solution : stocker les objets dans une base de donnée! La persistance par mapping objet/BD relationelle On stocke l'état d'un objet dans une base de donnée.La persistance par sérialisation Défauts nombreux… Gestion des versions. . maintenance… Pas de requêtes complexes… Ex : on sérialize mille comptes bancaires. Ex : la classe Personne possède deux attributs nom et prenom. On décompose chaque objet en une suite de variables dont on stockera la valeur dans une ou plusieurs tables. Permet des requêtes complexes.

JavaBlend (Sun). Mais SQL dur à tester/debugger… source de nombreuses erreurs… .La persistance par mapping objet/BD relationelle La persistance par mapping objet/BD relationelle Pas si simple… Détermination de l'état d'un objet parfois difficile. Aujourd'hui la plupart des gens font ça à la main avec JDBC ou SQL/J. tout un art… Il existe des produits pour nous y aider… TopLink (WebGain).

Plus de mapping ! Object Query Language (OQL) permet de manipuler les objets… Relations entre les objets évidentes (plus de join…) Bonnes performances mais mauvaise scalabilité. Ils utilisent un mécanisme de persistance (parmi ceux présentés) Ils servent à représenter sous forme d'objets des données situées dans une base de donnée Le plus souvent un objet = une ou plusieurs ligne(s) dans une ou plusieurs table(s) . Qu'est-ce qu'un Entity Bean Ce sont des objets qui savent se mapper dans une base de donnée.La persistance à l'aide d'une BD Objet Les Base de données objet stockent directement des objets.

Mais au fait. dans une instance d'un entity bean. note. On peut associer des méthodes simples pour manipuler ces données… On va gagner la couche middleware ! Exemple avec un compte bancaire On lit les informations d'un compte bancaire en mémoire.Qu'est-ce qu'un Entity Bean Exemples Compte bancaire (No. examen. livre. Employé. entreprises. Vue plus compacte. service. On manipule ces données. on les modifie en changeant les valeurs des attributs d'instance. solde). pourquoi nous embêter à passer par des objets ? Plus facile à manipuler par programme. élève. Les données seront mises à jour dans la base de données automatiquement ! Instance d'un entity bean = une vue en mémoire des données physiques . Cours. produit. on regroupe les données dans un objet.

Il est nécessaire d'avoir une classe du type de la clé primaire du bean.Fichiers composant un entity bean Idem session beans : interface locale. unique pour chaque instance. du SGBD Ce sont des vues sur des données dans un SGBD . qui seront appelées par le container + des méthodes de manipulation simples des données. classe du bean. descripteur. Elle doit fournir certaines méthodes obligatoires. remote. local home. home. Clé primaire = un objet sérializable. Caractéristiques des entity beans Survivent aux crashes du serveur. Quelques particularités cependant La classe du bean se mappe dans une base de données. C'est la clé primaire au sens SQL.

il faut synchroniser les beans en mémoire pour qu'ils se rafraîchissent lorsque les données changent. Mais alors.Caractéristiques des entity beans Plusieurs instances d'entity beans peuvent représenter les mêmes données Plusieurs client peuvent accéder aux mêmes données (compte bancaire par exemple) Un seul thread par bean dans le modèle EJB. code plus simple à écrire. Caractéristiques des entity beans Pool d'instances d'un entity bean Partage d'instances par plusieurs clients. Mais oui ! On peut même modifier les données dans le SGBD depuis un mécanisme extérieur ! Dépend de la politique de transaction du bean. Recyclage des instances… Processus similaire aux session beans stateful… .

la méthode ejbStore() est appelée. Idem. sockets…) Deux méthodes de callback ejbActivate() : appelée par le container lorsque le bean va recevoir un nouvel EJBObject et de nouvelles données dont une clé primaire. . Dans ce callback on doit acquérir des ressources (socket) ejbPassivate() : appelée lorsque le bean va être swappé sur disque. au moment de l'activation. Il faut libérer les ressources. Elle s'occupe de sauvegarder l'état du bean dans une BD. Caractéristiques des entity beans Juste avant la passivation. Ceci est réalisé en appelant ejbLoad(). le bean doit lire son état depuis la BD.Caractéristiques des entity beans Pas si simple que pour les Session Beans Comment libérer les ressources (connexions.

. Peut se faire au moment du déploiement. le plus souvent avec JDBC/SQL.Caractéristiques des entity beans Deux manières d'assurer la persistance Bean Managed Entity Bean (BMP) Persistance effectuée à la main. relecture. Développement plus rapide… Grosse plus-value du modèle EJB. recherche. Réduit la taille du code. si la BD est relationnelle. Sauvegarde. tout est à faire par le programmeur + déterminer l'état d'un objet (peut devenir très difficile) Container Managed Persistence Bean (CMP) Tout est fait par le container ! On indique dans les descripteurs comment on veut que le container assure la persistance.

Création d'entity beans Suppression d'entity beans .

Similaire à un SELECT Se traduit par la présence de méthodes "finders" dans l'interface HOME findByPrimaryKey(…). findAll()… findCheapProducts()… Plus d'informations dans les prochains chapitres… Modifier les données sans passer par le bean . on peut avoir besoin de faire des recherches.Recherche d'entity beans Les entity beans correspondant à des lignes dans une BD.

. public java.EJBHome getEJBHome().ejb.EntityContext extends javax. Le this pour les EJB ! getPrimaryKey() : utile lorsqu'on écrit des entity en mode BMP On l'utilise depuis ejbLoad() pour savoir quelle donnée il faut lire.lang.EJBObject getEJBObject().ejb.ejb.lang.Contexte d'un entity bean public interface javax. public java.EJBContext { public javax. public javax.Principal getCallerPrincipal().Object getPrimaryKey(). public javax.EJBContext { public javax.EJBLocalObject getEJBLocalObject(). } Contexte d'un entity bean getEJBLocalObject() et getEJBObject() permettent d'obtenir une référence sur l'EJB Object associé au bean. public boolean getRollbackOnly().ejb. pour savoir quelle donnée il faut supprimer. public boolean isCallerInRole(java. } public interface javax. public void setRollbackOnly().ejb.String).EJBLocalHome getEJBLocalHome(). Depuis ejbRemove().security.ejb.ejb.

UNSA 2002 BMP entity beans Le premier type d'entity bean.Bean-Managed Persistent Entity Beans (BMP) Michel Buffa (buffa@unice.fr). Le programmeur doit assurer l'implémentation de toute la logique d'accès aux données. Typiquement. à l'aide de JDBC… .

Ces méthodes commencent toutes par ejbFind…() Ces méthodes sont utilisées pour rechercher des données dans une BD.ejb.io. Par exemple. appartenant à la même classe d'objets.EnterpriseBean implements java. public void ejbRemove(). toutes les Personnes… Ces méthodes ne sont nécessaires avec les Entity Beans CMP (Container Managed Persistence) . public void ejbLoad().ejb.EntityBean public interface javax. il est nécessaire d'implémenter des méthodes finders.EntityBean.ejb.EntityContext).ejb.Implémentation des BMP : les bases La classe du Bean doit dériver de javax.EnterpriseBean { public void setEntityContext(javax.ejb.ejb. public void unsetEntityContext(). } Recherche d'entity beans existants : ejbFind() Par rapport à l'interface javax. public void ejbActivate().Serializable { } public interface javax. public void ejbStore().EntityBean implements javax. public void ejbPassivate().

Les finders renvoient soit la clé primaire soit une Collection de clés primaires. } /** Finds all the product entity beans.. keys... */ Returns a Collection of primary public Collection ejbFindAllProducts() { . . } Quelques règles à propos des méthodes finder Toutes les méthodes commencent par ejbFind Au moins une méthode finder : ejbFindByPrimaryKey On peut avoir plusieurs méthodes.. } /** Finds the most recently placed order */ public OrderPK ejbFindMostRecentOrder() { .. avec des noms et des paramètres différents. } /** Finds all Bank Accounts that have at least a minimum balance...Quelques exemples de méthodes finder /** Finds the unique bank account indexed by primary key key */ public AccountPK ejbFindByPrimaryKey(AccountPK key) { . */ public Collection ejbFindBigAccounts(int minimum) { .. Returns a Collection of primary keys.

Pour chaque finder dans le bean. il faut une méthode correspondante dans l'objet Home Dans le Home : public Account findBigAccounts(int minimum). c'est un EJB Object qui est renvoyé. la méthode renvoie la clé primaire au container.Quelques règles à propos des méthodes finder Comme avec ejbCreate(). Ils passent par les méthodes de l'objet Home. Dans le Home.. Dans le Bean : public AccountPK ejbFindBigAccounts(int minimum) { . il y a des différences entre la signature de la méthode dans le Home ou dans le Bean : Dans le bean. les clients n'invoquent pas directement les méthodes finders du bean. on ajoute ejb comme préfixe dans la méthode du Bean Comment la méthode du Bean est-elle appelée ? .. Le nom change. } Quelques règles à propos des méthodes finder Comme pour ejbCreate().

pour pouvoir tester le bean via un client de test.. On écrira donc les interfaces Remote… . Mais pour nos essais.Quelques règles à propos des méthodes finder Les finders peuvent renvoyer des Collections public Collection findAllProducts(). Le container la transforme en Collection d'EJB Objects Exemple : un compte bancaire Remarque : en production. on aura besoin surtout des interfaces locales. } findindAllProducts() renvoie une Collection de clés primaires au container. public Collection ejbFindAllProducts() { .. pour un tel bean. on va devoir l'invoquer à distance.

// Getter/setter methods on Entity Bean fields public double getBalance() throws RemoteException. RemoteException. public void setAccountID(String id) throws RemoteException. import java.rmi. public String getOwnerName() throws RemoteException. RemoteException. * This interface is what clients operate on when they interact with * beans.*.RemoteException. public String getAccountID() throws RemoteException.java : l'interface Remote package examples. import javax. */ public interface Account extends EJBObject { /** Deposits amt into account.Exemple : un compte bancaire Account. /** Withdraws amt from bank account. the * implemented object is called the EJB object. which delegates * invocations to the actual bean. * @throw AccountException thrown if amt < available balance */ public void withdraw(double amt) throws AccountException. public void setOwnerName(String name) throws RemoteException. The container will implement this interface. } . /** This is the remote interface for AccountBean.ejb.*/ public void deposit(double amt) throws AccountException.

.*/ public interface AccountLocal extends EJBLocalObject { /** Deposits amt into account. public String getAccountID(). The container will implement this interface.util. */ Account create(String accountID. String ownerName) throws CreateException..*. This * interface is implemented by the EJB container's tools . which delegates * invocations to the actual bean. } Account. /** This is the local interface for AccountBean.*.Collection. import javax. import java. RemoteException..rmi. * which corresponds to the ejbCreate() method in AccountBean.RemoteException. * This method creates the EJB object.the * implemented object is called the home object. // Getter/setter methods on Entity Bean fields public double getBalance().ejb.Account. the * implemented object is called the local object. . * This interface is what clients operate on when they interact with * beans. public void setOwnerName(String name).java : l'interface Local package examples. public String getOwnerName(). /** This is the home interface for Account. import javax. import java. * @param accountID The number of the account (unique) * @param ownerName The name of the person who owns the account * @return The newly created local object. /** Withdraws amt from bank account.java : l'interface Home package examples. public void setAccountID(String id).ejb.*/ public void deposit(double amt) throws AccountException. * @throw AccountException thrown in amt < available balance */ public void withdraw(double amt) throws AccountException. */ public interface AccountHome extends EJBHome { /** We define a single create() method is in this home interface. which * is a factory for EJB objects.

.ejb. * @param accountID The number of the account (unique) * @param ownerName The name of the person who owns the account * @return The newly created local object.. This * interface is implemented by the EJB container's tools . which * is a factory for local EJB objects. /* This is the local home interface for Account.Account... It returns the total of all accounts in the bank. import javax.the * implemented object is called the local home object. * This method creates the local EJB object. */ AccountLocal create(String accountID. RemoteException. /** Finds a Account by its owner name (assume there is only 1) */ public Collection findByOwnerName(String name) throws FinderException. /** This home business method is independent of any particular * account. * Notice that the local home interface returns a * local interface. whereas the bean returns a PK. .java : l'interface Local Home package examples. */ public interface AccountLocalHome extends EJBLocalHome { /** We define a single create() method is in this home interface.*. * Notice we don't throw RemoteExceptions because we are * local not remote. /** Finds a Account by its primary Key (Account ID) */ public Account findByPrimaryKey(AccountPK key) throws FinderException. RemoteException.. } Account.java : l'interface Home (suite) .*/ public double getTotalBankValue() throws AccountException. import java. RemoteException. String ownerName) throws CreateException. * which corresponds to the ejbCreate() method in AccountBean.Collection.util.

. } public boolean equals(Object account) { } } // Requiered ! // Requiered. import java. */ public double getTotalBankValue() throws AccountException.*/ public class AccountPK implements java.io.Serializable. /** Primary Key class for Account.java : l'interface Local Home (suite) . /** Finds a Account by its owner's name (assume there is only 1 */ public Collection findByOwnerName(String name) throws FinderException.java : la classe de la clé primaire package examples..io. } public AccountPK() {} public String toString() { return accountID.Serializable { public String accountID. } public int hashCode() { return accountID.hashCode().Account. It returns the total of all the bank * accounts in the bank..accountID = id. } AccountPK. /** Finds a Account by its primary Key (Account ID) */ public AccountLocal findByPrimaryKey(AccountPK key) throws FinderException. // example : "ABC-123-0000" public AccountPK(String id) { this.accountID. for being able to be stored in hastables // Requiered ! return ((AccountPK)account). /** This home business method is independent of any particular * account instance.equals(accountID).

Les attributs qui font partie de l'état persistant de l'objet. AccountBean. /** Demonstration Bean-Managed Persistent Entity Bean.*/ public class AccountBean implements EntityBean { protected EntityContext ctx... .*.*. 3.. import java.rmi.RemoteException. import javax.ejb. 2. * This Entity Bean represents a Bank Account. nous le décomposons en 3 parties 1..AccountBean.").naming. // Bean-managed state fields private String accountID. methods continue .sql.out. Les méthodes business (la logique métier) Les méthodes requises par la specification EJB.*. import java. public AccountBean() { System.util. // Primary Key private String ownerName.println("New Bank Account Entity Bean Java Object created by EJB Container.java : les attributs package examples. import java.java Comme le source est long.*. } . import javax. private double balance.

. ownerName = name. return balance.out. return ownerName. if (amt > balance) { throw new AccountException("Your balance is " + balance + "! } balance -= amt.AccountBean.*/ public void deposit(double amt) throws AccountException { System."). return accountID.out."). You cannot withdraw " + amt + "!"). } /** Withdraws amt from bank account. * @throw AccountException thrown in amt < available balance */ public void withdraw(double amt) throws AccountException { System...println("setOwnerName() called.out.out."). AccountBean.. } public void setOwnerName(String name) { System.."). continued . } public String getAccountID() { System.").").println("getOwnerName() called.println("getBalance() called. balance += amt.java : méthodes business (1) .println("getAccountID() called..out. } .out. } public String getOwnerName() { System. // Business Logic Method /** Deposits amt into account. } .java : méthodes business (2) // Getter/setter methods on Entity Bean fields public double getBalance() { System.println("withdraw(" + amt + ") called.println("deposit(" + amt + ") called.

*/ public double ejbHomeGetTotalBankValue() throws AccountException { PreparedStatement pstmt = null.executeQuery(). } catch (Exception e) {…} } throw new AccountException("Error!"). } .close(). .. this.println("ejbHomeGetTotalBankValue()").java : méthodes business (3) public void setAccountID(String id) { System... ResultSet rs = pstmt.java : méthodes business (4) . } } catch (Exception e) { e.out. } /** This home business method is independent of any * particular account instance.println("setAccountID() called.next()) { return rs. Connection conn = null.printStackTrace()..prepareStatement("select sum(balance) as total from … AccountBean."). try { System. pstmt = conn. /* Acquire DB connection */ conn = getConnection().accountID = id.getDouble("total"). /* Return the sum */ if (rs.out. } finally { /* Release DB Connection for other beans */ try { if (pstmt != null) pstmt.AccountBean. } catch (Exception e) {…} try { if (conn != null) conn.close(). /* Get the total of all accounts */ accounts"). It returns the total * of all the bank accounts in the bank. throw new AccountException(e).

println("Could not locate datasource! e. ejbLoad(). Delete) ? En EJB : ejbCreate().err. Read. javax.AccountBean. un autre bean peut l'utiliser ! Pooling réalisé par JDBC 2. AccountBean. ejbRemove() .lookup("java:comp/env/jdbc/ejbPool"). } } } // End of business methods ! Reason:").sql.java : méthodes business (6) Remarques Ouverture de la connexion à la DB via JNDI On ferme la connexion après chaque requête : permet le pooling des connexions ! Lorsque la connexion n'est pas utilisée.0 ! Vous êtes prêt pour le CRUD (Create..getConnection(). throw e. return ds. * @return The JDBC connection */ public Connection getConnection() throws Exception { try { Context ctx = new InitialContext().DataSource ds = (javax.sql.. ejbFind(). ejbStore. /** Gets JDBC connection from the connection pool.java : méthodes business (5) .printStackTrace().DataSource) ctx. } catch (Exception e) { System. Update.

println("ejbRemove() called. } finally { /* 4) Release the DB Connection */ try { if (pstmt != null) pstmt. we know which data instance. */ public void ejbActivate() { System. /* 2) Remove account from the DB*/ pstmt = conn.out. Connection conn = null. AccountBean.close().close(). String id = pk. * So how does this method know which instance in the database to delete? * The answer is to query the container by calling the entity context object."). } } catch (Exception ex) { throw new EJBException(ex. try { /* 1) Acquire a new JDBC Connection */ conn = getConnection(). id).*/ public void ejbPassivate() { System.AccountBean.println("ejbPassivate () called.prepareStatement("delete from accounts where id = ?")."). */ AccountPK pk = (AccountPK) ctx.toString()). } catch (Exception e) {} try { if (conn != null) conn.java : les méthodes ejb…(2) /* 3) Throw a system-level exception if something bad happened.setString(1. PreparedStatement pstmt = null. that we should delete from the DB.out. } catch (Exception e) {} } } /** Called by Container.remove().accountID.*/ public void ejbRemove() { System."). */ if (pstmt.java : les méthodes ejb…(1) // EJB-required methods /** Called by Container. pstmt.out. Releases held resources for passivation.getPrimaryKey(). /* Remember that an entity bean class can be used to represent different data instances. keyed * by the PK.executeUpdate() == 0) { throw new RemoteException("Account " + pk + " failed to be removed from the database"). Implementation can acquire needed resources. By * retrieving the primary key from the entity context. } /** Removes entity bean data from the database. Corresponds to when client calls home.println("ejbActivate() called. } .

close(). id). public void ejbStore() { System. querying by account ID */ pstmt = conn. balance from accounts where id = ?").getString("ownerName"). /* 2) Get account from the DB.prepareStatement("select ownerName."). ex).getDouble("balance").").*/ AccountBean.. .next(). Connection conn = null.*/ . PreparedStatement pstmt = null. } finally { /* 3) Release the DB Connection */ try { if (pstmt != null) pstmt.out..java : les méthodes ejb…(4) }catch (Exception ex) { throw new EJBException("Account " + pk + " failed to load from database".out.. */ AccountPK pk = (AccountPK) ctx. public void ejbLoad() { System.AccountBean. Updates the database to reflect the current values of this * in-memory entity bean instance. so we know which * instance to load. ownerName = rs. try { /* 1) Acquire a new DB Connection */ conn = getConnection(). } catch (Exception e) {} try { if (conn != null) conn. Updates the in-memory entity bean object to reflect the current * value stored in the database..println("ejbStore() called.getPrimaryKey().setString(1.java : les méthodes ejb…(3) /** Called by the container. . try { /* 1) Acquire a new DB Connection */ conn = getConnection(). /* Again. query the Entity Context to get the current Primary Key. Connection conn = null.close(). String id = pk. PreparedStatement pstmt = null. ResultSet rs = pstmt. rs.println("ejbLoad() called.executeQuery(). pstmt. } catch (Exception e) {} } } /** Called from the Container. balance = rs.accountID.

*/ public void unsetEntityContext() { System. Now.ownerName = ownerName. pstmt. * When the client calls the Home Object's create() method. ex). ownerName). Associates this bean instance with a particular context. } /** Called after ejbCreate(). the Home Object then calls this * ejbCreate() method. } catch (Exception ex) { throw new EJBException("Account " + accountID + " failed to save to database". Connection conn = null. pstmt. try { System.out.setString(3. the Bean can retrieve its EJBObject from its context. this. } catch (Exception e) {} try { if (conn != null) conn. and pass it .prepareStatement("update accounts set ownerName = ?. We can query * the bean properties which customize the bean here.balance = 0.java : les méthodes ejb…(5) /* 2) Store account in DB */ pstmt = conn. } AccountBean. this. this. } catch (Exception e) {} } } /** Called by the container.ctx = ctx.out.accountID = accountID. balance). */ public void ejbPostCreate(String accountID. String ownerName) { } /** This is the initialization method that corresponds to the create() method in the Home Interface. accountID).out.AccountBean. this.java : les méthodes ejb…(6) /** Called by Container. */ public void setEntityContext(EntityContext ctx) { System.close().executeUpdate().setDouble(2. String ownerName) throws CreateException { PreparedStatement pstmt = null.println("setEntityContext called"). pstmt.println("ejbCreate() called. * @return The primary key for this account */ public AccountPK ejbCreate(String accountID. pstmt.close().setString(1. Disassociates this bean instance with a particular context environment. this. /* Acquire DB connection */ conn = getConnection()."). } finally { /* 3) Release the DB Connection */ try { if (pstmt != null) pstmt. balance = ? where id = ?").println("unsetEntityContext called").ctx = null. * as a 'this' argument.

pstmt.java : les méthodes ejb…(8) /** Finds a Account by its primary Key */ public AccountPK ejbFindByPrimaryKey(AccountPK key) throws FinderException { PreparedStatement pstmt = null.setString(2. }catch (Exception e) { throw new CreateException(e.close(). accountID). ownerName.executeUpdate(). pstmt. Connection conn = null. /* Acquire DB connection */ conn = getConnection().close().close().setString(1.toString()). } catch (Exception e) {} } } .prepareStatement("insert into accounts (id. /* No errors occurred.setDouble(3. key.java : les méthodes ejb…(7) /* insert the account into the database */ pstmt = conn. ?. } catch (Exception e) {} try { if (conn != null) conn. /* Find the Entity in the DB */ pstmt = conn.toString()).close(). rs.next(). }finally { /* Release DB Connection for other beans */ try { if (pstmt != null) pstmt. }finally { /* Release DB Connection for other beans */ try { if (pstmt != null) pstmt.AccountBean. pstmt.println("ejbFindByPrimaryKey(" + key + ") called"). balance) values (?. balance). try { System. } catch (Exception e) {} try { if (conn != null) conn. so return the Primary Key */ return key. } catch (Exception e) { throw new FinderException(e. ownerName). } catch (Exception e) {} } } AccountBean. pstmt.executeQuery().out.prepareStatement("select id from accounts where id = ?"). ?)"). ResultSet rs = pstmt.setString(1. pstmt. /* Generate the Primary Key and return it */ return new AccountPK(accountID).toString()).

close(). v. /* Find the primary keys in the DB */ pstmt = conn.getString("id").setString(1. Connection conn = null. } /* Return the vector of primary keys */ return v.toString()). } catch (Exception e) {} try { if (conn != null) conn.executeQuery().prepareStatement("select id from accounts where ownerName = ?"). try { System. /* Insert every primary key found into a vector */ while (rs.out.java : les méthodes ejb…(10) finally { /* Release DB Connection for other beans */ try { if (pstmt != null) pstmt.println("ejbFindByOwnerName(" + name + ") called"). pstmt. name).java : les méthodes ejb…(9) /** Finds a Account by its Name */ public Collection ejbFindByOwnerName(String name) throws FinderException { PreparedStatement pstmt = null.addElement(new AccountPK(id)).next()) { String id = rs. Vector v = new Vector(). } AccountBean. ResultSet rs = pstmt. /* Acquire DB connection */ conn = getConnection(). } catch (Exception e) {} } } } // OUF ! .AccountBean.close(). } catch (Exception e) { throw new FinderException(e.

toString()). } public AccountException(String s) { super(s).java package examples.AccountBean. } public AccountException(Exception e) { super(e.ejbinfo. } } .com AccountException. /** Exceptions thrown by Accounts */ public class AccountException extends Exception { public AccountException() { super().java : remarques JDBC est intelligent lorsqu'on utilise les prepared statements Utilisation de cache et de statistiques sur les reqêtes… Cf "How Prepared Statements Greatly Improve Performance" sur www.

rmi.java (1) package examples.out.*. /* Find an account */ Iterator i = home. import javax.getBalance()).hasNext()) { account = (Account) i. import java. */ System. AccountHome home = (AccountHome) javax.*.findByOwnerName("John Smith"). . /* Retrieve the resulting balance.rmi.*.util.*.next(). if (i. /* Deposit $100 into the account */ account. account balance = " + account.println("After depositing 100.the * factory for Account EJB Objects */ Context ctx = new InitialContext(System.getBalance()).err.narrow(obj.lookup("AccountHome").println("Total of all accounts in bank initially = " + home.deposit(100). import javax. } /* Call the balance() method.class). AccountHome.getProperties()).*. */ public class AccountClient { public static void main(String[] args) throws Exception { Account account = null.Client.println("Initial Balance = " + account.iterator(). /* Use the factory to create the Account EJB Object */ home. } else { throw new Exception("Could not find account"). import java.rmi. try { /* Get a reference to the Account Home Object . and print it */ System.ejb.out. Object obj = ctx. /** Sample client code which manipulates a Bank Account Entity Bean.getTotalBankValue()).java (2) System.PortableRemoteObject. "John Smith").naming.create("123-456-7890". import javax. Client.

println("Now trying to withdraw $150.Client.withdraw(150).. } Balance = " Now call * find() again. */ account = null. This should generate an exception. } } } . the Primary Key).getPrimaryKey().findByPrimaryKey(pk). /* Retrieve the Primary Key from the EJB Object */ AccountPK pk = (AccountPK) account. e.println("Caught exception!"). /* Try to withdraw $150 */ System. /* Print out current balance */ System..getTotalBankValue()). + account.remove(). if (account != null) { account.getBalance()). account."). * (i. account = home.java (3) System. } catch (Exception e) { System.e.out.out.out. this time querying on Account ID Client.println("Found account with ID " + pk + ".out.println("Destroying account.out.println("Total of all accounts in bank now = " + home.printStackTrace(). /* Release our old EJB Object reference.java (4) finally { /* Destroy the Entity permanently */ try { System.printStackTrace(). } } catch (Exception e) { e."). which is more than is currently available.

Account</remote> <local-home>examples.com/dtd/ejb-jar_2_0.Descripteur de déploiement (1) <?xml version="1.sun.0"?> <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems.AccountHome</home> <remote>examples.sql.dtd'> <ejb-jar> <enterprise-beans> <entity> <ejb-name>Account</ejb-name> <home>examples.//DTD Enterprise JavaBeans 2.AccountBean</ejb-class> <persistence-type>Bean</persistence-type> <prim-key-class>examples.AccountPK</prim-key-class> <reentrant>False</reentrant> <resource-ref> <res-ref-name>jdbc/ejbPool</res-ref-name> <res-type>javax.AccountLocal</local> <ejb-class>examples. Descripteur de déploiement (2) <assembly-descriptor> <container-transaction> <method> <ejb-name>Account</ejb-name> <method-intf>Local</method-intf> <method-name>*</method-name> </method> <method> <ejb-name>Account</ejb-name> <method-intf>Remote</method-intf> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar> ..AccountLocalHome</local-home> <local>examples.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </entity> </enterprise-beans> . Inc..0//EN' 'http://java.

spécifie les noms… La table dans la DataBase Pour pouvoir exécuter cet exemple. il est nécessaire d'avoir crée la table accounts dans une base de donnée : drop table accounts. ownername varchar(64). balance numeric(18)). Configure JNDI.Descripteur spécifique Change selon le vendeur de container. create table accounts (id varchar(64). .

Exécution. getBalance() called.AccountException: Your balance is 100.. les sorties côté client Total of all accounts in bank initially = 1200000.0 After depositing 100. which is more than is currently available.0 Initial Balance = 0. setEntityContext called ejbFindByOwnerName(John Smith) called ejbLoad() called. setEntityContext called ejbHomeGetTotalBankValue() called ejbCreate() called. ejbStore() called. ejbRemove() called. account balance = 100. ejbLoad() called. This should generate an exception. ejbStore() called.0) called. ejbLoad() called.. ejbStore() called. ejbLoad() called. withdraw(150.0 Found account with ID 123-456-7890. ejbStore() called.0! 150. getBalance() called. New Bank Account Entity Bean Java Object created by EJB Container. deposit(100. Caught exception! examples. getBalance() called.0) called. Balance = 100.0 Now trying to withdraw $150.0 Total of all accounts in bank now = 1200100. ejbStore() called. You cannot withdraw . ejbStore() called. ejbHomeGetTotalBankValue() called ejbFindByPrimaryKey(123-456-7890) called ejbLoad() called. les sorties côté serveur New Bank Account Entity Bean Java Object created by EJB Container. ejbLoad() called.0! Destroying account. Exécution.

UNSA 2002 .BMP entity bean : cycle de vie Container-Managed Persistent Entity Beans (CMP) Michel Buffa (buffa@unice.fr).

Plus de performance ?! Comparer avec les garbage collectors… Attention au choix du container… Les CMP : un réel besoin Le vendeur de beans ne veut pas être dépendant du moyen assuré pour réaliser la persistance. sans le source le plus souvent… Le client décide où il va stocker les données CMP répond au besoin de ce découpage .CMP entity beans Le second type d'entity bean. Le container assure l'implémentation de toute la logique d'accès aux données. Il distribue ses beans. Ceci simplifie grandement le développement ! Moins de bugs. Code plus court.NET dit le contraire ! .

sans logique données (pas de JDBC…) Le container génère le code JDBC dans une sous-classe de la classe fournie par le développeur. Un bean CMP = la classe du développeur + la sous-classe générée par le container. Découpage propre ! .Les CMP : découpage par génération de sous-classe Le développeur écrit son bean CMP.

Les CMP : pas de déclaration d'attributs ! Le container gère la persistance à sa manière. s'il faut synchroniser la DB. } // PK CMP // CMP Subclass public class AccountBeanSubClass extends AccountBean { public String accountID. EJB 2. public String ownerName. comment y accède-t-on ? Où les déclare-t-on ? Les CMP : pas de déclaration d'attributs ! BMP public class AccountBean implements EntityBean { public String accountID.. Par exemple.0 fait carrément sauter la déclaration des attributs dans le code fourni par le développeur ! Les attributs sont déclarés dans la sous-classe générée par le container ! Mais alors.. public String ownerName. public double balance.... pour éviter du code sale.methods. public double balance. } // PK .. etc… Bref. . . mettre des marqueurs sur les attributs pour voir s'ils ont changé..methods..

CMP accesseurs et modifieurs dans la sous-classe
BMP
public class AccountBean implements EntityBean { public String accountID; public String ownerName; public double balance; public String getOwnerName() { return ownerName; } public void setOwnerName(String ownerName) { this.ownerName = ownerName; } ...other methods... } // PK

CMP accesseurs et modifieurs dans la sous-classe
CMP
// CMP subclass public class AccountBeanSubClass extends AccountBean { public String accountID; public String ownerName; public double balance; public String getOwnerName() { return ownerName; } public void setOwnerName(String ownerName) { this.ownerName = ownerName; } ...other methods... } // Puisque c'est ici que sont déclarés les attributs // PK

CMP : mais alors, que mettre dans la classe du bean ?
Problème : on ne peut avoir de get/set car on n'a pas accès aux attributs… Mais on a besoin de les appeler !
// BMP public class CartBean implements EntityBean { ... public float getTotal() { return this.getSubtotal() + this.getTaxes(); } ... }

CMP : des get/set abstraits !
// CMP superclass public abstract class CartBean implements EntityBean { // no fields

// abstract get/set methods public abstract float getSubTotal(); public abstract float getTaxes();

// other business methods public float getTotal() { return this.getSubtotal() + this.getTaxes(); }

// EJB required methods follow }

CMP : schéma de persistance abstrait
Le container sait quoi générer dans la sous-classe grâce aux méthodes abstraites de la classe du bean, Mais aussi grâce au descripteur.
... <cmp-version>2.x</cmp-version> <abstract-schema-name>AccountBean</abstract-schema-name> <cmp-field> <field-name>accountID</field-name> </cmp-field> <cmp-field> <field-name>ownerName</field-name> </cmp-field> <cmp-field> <field-name>balance</field-name> </cmp-field> <primkey-field>accountID</primkey-field> ...

CMP : un langage de requêtes !
EJB 2.0 fournit EJB QL, un langage de requêtes! Utile pour écrire les finders. BMP
public Account findBigAccounts(int minimum); // HOME public Collections ejbFindBigAccounts(int minimum) { // Bean // Perform JDBC, and return primary keys for // all accounts whose balance is greater // than the minimum passed in }

EJB-QL : un langage de requêtes !
Avec CMP, on écrit la requête EJB-QL correspondant à la méthode finder dans le descripteur du bean Ex de requête EJB-QL qui sélectionne tous les comptes bancaires
SELECT OBJECT(a) FROM Account AS a WHERE a.accountID IS NOT NULL

Ex de requête EJB-QL qui sélectionne tous les comptes bancaires dont le solde est > paramètre minimum de ejbFindBigAccounts(int minimum)
SELECT OBJECT(a) FROM Account AS a WHERE a.balance > ?1

CMP : quelques attributs quand même…
Remarque : tous les champs n'ont pas besoin d'être persistants… Les contextes sont déclarés normalement dans la classe du bean par exemple… Le container ne s'occupera pas des champs déclarés dans la classe du bean.

CMP : développement/déploiement

Méthodes ejbSelect()
Les beans CMP peuvent avoir des méthodes ejbSelect()… Ces méthodes sont des finders à usage interne, non exposés aux clients du bean, Utile lorsqu'on a des entity beans CMP qui ont des relations avec des données externes, comme d'autres entity beans. Par exemple : ejbHomeGetTotalBankValue() que nous avons vu dans l'exemple BMP
Avec BMP, cette méthode faisait un SELECT, Avec CMP, on n'a pas à écrire de requête SQL, elle appellera à la place une méthode ejbSelect() On indiquera au container quelle requête EJB-QL associer à ejbSelect()

Méthodes ejbSelect()
Exemple
public abstract Collection ejbSelectAllAccountBalances() throws FinderException; public double ejbHomeGetTotalBankValue() throws Exception { // Get a collection of bank account balances Collection c = this.ejbSelectAllAccountBalances(); // Loop through collection and return sum... ... }

Remarques
Comme les finders, les méthodes ejbSelect() peuvent renvoyer des entity beans. Mais elles peuvent aussi renvoyer des attributs gérés par le container ! Dans l'exemple, c'est une collection de valeurs double qui est renvoyée.

Méthodes ejbSelect()
La requête EJB-QL associée à chaque méthode finder se trouve dans le descripteur de déploiement. Entre un entity bean CMP et un entity bean BMP, rien ne change vis-à-vis du client. Les interfaces peuvent être identiques.
Seul le descripteur, Et la classe du Bean changent !

import javax. } . public String getDescription() throws RemoteException.CMP : un exemple Une ligne de produits génériques Product. the implemented object is called the EJB Object.rmi.*.RemoteException. public void setDescription(String description) throws RemoteException.ejb. import java. public String getProductID() throws RemoteException.java : l'interface remote package examples. public void setName(String name) throws RemoteException. The EJB container * will implement this interface. public double getBasePrice() throws RemoteException. */ public interface Product extends EJBObject { public String getName() throws RemoteException. public void setBasePrice(double price) throws RemoteException. This remote interface is * what remote clients operate on when they interact with beans. /** These are the public business methods of ProductBean. * which delegates invocations to instances of the entity bean class.

which corresponds to the * ejbCreate() method in the bean class. * One create() method is in this Home Interface. This interface is implemented by the The implemented object is called the Home Object. public double getBasePrice(). */ public interface ProductHome extends EJBHome { /* Creates a product * @param productID The number of the product (unique) * @param name The name of the product * @param description Product description * @param basePrice Base Price of product * @return The newly created EJB Object. /** These are the public business methods of ProductBean. String description. * factory for EJB Objects. public void setBasePrice(double price). import javax. String name. and serves as a . the implemented object is called the EJB local * Object. which delegates invocations to instances of the entity bean class. double basePrice) throws CreateException. } ProductHome.*.Collection. import javax.java : l'interface locale package examples.ejb..ejb. import java.RemoteException. * EJB container. public void setDescription(String description). /** This is the home interface for Product.java : l'interface home (1) package examples..util. import java. */ public interface ProductLocal extends EJBLocalObject { public String getName().rmi.ProductLocal. */ Product create(String productID. The EJB container * will implement this interface. This local interface is * what local clients operate on when they interact with beans.*. public void setName(String name). . RemoteException. public String getDescription(). public String getProductID().

public Collection findExpensiveProducts(double minPrice) throws FinderException. import javax. } These are implemented by the container.ProductHome. public Collection findByDescription(String description) throws FinderException. double basePrice) throws CreateException. public Collection findCheapProducts(double maxPrice) throws FinderException. public Collection findByBasePrice(double basePrice) throws FinderException.. public Collection findByDescription(String description) throws FinderException. RemoteException. RemoteException.Collection.*. // Finder methods. RemoteException. RemoteException. // Finder methods. You can customize the // functionality of these methods in the deployment descriptor through EJB-QL and ProductLocalHome.ejb. RemoteException. public Collection findCheapProducts(double maxPrice) throws FinderException. public Collection findByName(String name) throws FinderException.. } . public Collection findByBasePrice(double basePrice) throws FinderException. public Collection findExpensiveProducts(double minPrice) throws FinderException. public Product findByPrimaryKey(ProductPK key) throws FinderException. public Collection findAllProducts() throws FinderException. RemoteException. public Collection findByName(String name) throws FinderException. String name. import java.java : interface local home package examples. // container tools. public Collection findAllProducts() throws FinderException.util. public interface ProductHome extends EJBLocalHome { Product create(String productID. RemoteException.java : l'interface home (2) . public Product findByPrimaryKey(String key) throws FinderException. String description.

ProductPK.java : la classe de la clé primaire (1)
package examples; import java.io.Serializable; /** Primary Key class for our 'Product' Container-Managed Entity Bean */ public class ProductPK implements java.io.Serializable { /* Note that the primary key fields must be a subset of the the container-managed * fields. * The fields we are marking as container-managed in our Bean are productID, * name, desc, and basePrice. * Therefore our PK fields need to be from that set. */ public String productID; public ProductPK(String productID) { this.productID = productID; } public ProductPK() {} ...

ProductPK.java : la classe de la clé primaire (2)
... public String toString() { return productID.toString(); }

public int hashCode() { return productID.hashCode(); }

public boolean equals(Object prod) { return ((ProductPK)prod).productID.equals(productID); } }

ProductPK.java : remarques
Comme avec les beans BMP, la classe de la clé primaire doit être sérialisable. Comme le container assure la persistance, les attributs doivent avoir été déclaré dans le descripteur ! Il vaut mieux utiliser une classe pour la clé primaire, plutôt que déclarer un attribut clé primaire
Meilleure encapsulation! <primkey-field>productID</primkey-field> : A EVITER !

ProductBean.java : la classe du bean (1)
package examples; import javax.ejb.*; /** Entity Bean which demonstrates Container-Managed persistence. * This is a product that's persistent. * a base price. */ public abstract class ProductBean implements EntityBean { protected EntityContext ctx; public ProductBean() {} // Begin abstract get/set methods public abstract String getName(); public abstract void setName(String name); public abstract String getDescription(); public abstract void setDescription(String description); public abstract double getBasePrice(); public abstract void setBasePrice(double price); public abstract String getProductID(); public abstract void setProductID(String productID); // End abstract get/set methods ... It has an ID #, a name, a description, and

ProductBean.java : la classe du bean (2)
// Begin EJB-required methods. The methods below are called by the Container,

// and never called by client code. /** Called by Container. Implementation can acquire needed resources. */ public void ejbActivate() { System.out.println("ejbActivate() called."); } /** EJB Container calls this method right before it removes the Entity Bean from * the database. * Corresponds to when client calls home.remove(). */ public void ejbRemove() { System.out.println("ejbRemove() called."); } /** Called by Container. Releases held resources for passivation. */ public void ejbPassivate() { System.out.println("ejbPassivate () called."); } ...

ProductBean.java : la classe du bean (3)
/** Called from the Container. Updates the entity bean instance to reflect the * current value stored in the database. * Since we're using Container-Managed Persistence, we can leave this method * blank. The EJB Container will automatically load us in the subclass. */ public void ejbLoad() { System.out.println("ejbLoad() called."); } /** Called from the Container. Updates the database to reflect the current * values of this in-memory Entity Bean instance representation. * Since we're using Container-Managed Persistence, we can leave this method * blank. The EJB Container will automatically save us in the subclass. */ public void ejbStore() { System.out.println("ejbStore() called."); } /** Called by Container. * context. Associates this Bean instance with a particular Once done, we can query the Context for environment info */

public void setEntityContext(EntityContext ctx) { System.out.println("setEntityContext called"); this.ctx = ctx; } ...

ProductBean.java : la classe du bean (4)
/** Called by Container. particular * context environment.*/ public void unsetEntityContext() { System.out.println("unsetEntityContext called"); this.ctx = null; } /** Called after ejbCreate(). EJBObject from its Now, the Bean can retrieve its Disassociates this Bean instance with a

* context, and pass it as a 'this' argument. */ public void ejbPostCreate(String productID, String name, String description, double basePrice) { System.out.println("ejbPostCreate() called"); }

ProductBean.java : la classe du bean (5)
/** This is the initialization method that corresponds to the create() method in * the Home Interface. * When the client calls the Home Object's create() method, the Home Object then * calls this ejbCreate() method. * We need to initialize our Bean's fields with the parameters passed from the * client, so that the Container can create the corresponding database entries in * the subclass after this method completes. */ public String ejbCreate(String productID, String name, String description, double basePrice) { System.out.println("ejbCreate() called"); setProductID(productID); setName(name); setDescription(description); setBasePrice(basePrice); return productID; } // No finder methods (they are implemented by Container) // End of EJB-required methods }

ProductBean.java, sans les commentaires
package examples; import javax.ejb.*; public abstract class ProductBean implements EntityBean { protected EntityContext ctx; public abstract String getName(); public abstract void setName(String name); public abstract String getDescription(); public abstract void setDescription(String description); public abstract double getBasePrice(); public abstract void setBasePrice(double price); public abstract String getProductID(); public abstract void setProductID(String productID); public void ejbActivate() {} public void ejbRemove() {} public void ejbPassivate() {} public void ejbLoad() {} public void ejbStore() {} public void setEntityContext(EntityContext ctx) { this.ctx = ctx; } public void unsetEntityContext() { this.ctx = null; } public void ejbPostCreate(String productID, String name, String description, double basePrice) {} public String ejbCreate(String productID, String name, String description, double basePrice) { setProductID(productID); setName(name); setDescription(description); setBasePrice(basePrice); return productID; } }

ProductBean.java : remarques
Code très court ! Ce bean est bien plus complexe que l'exemple BMP déjà étudié, qui était si long !
Nombreuses méthodes finder, Plus d'attributs persistants, Taille 40% inférieure, au moins ! Pas de JDBC, moins de risque d'erreurs

ProductPK</prim-key-class> <reentrant>False</reentrant> <cmp-version>2...xml : le descripteur de déploiement(2) <abstract-schema-name>ProductBean</abstract-schema-name> <cmp-field> <field-name>productID</field-name> </cmp-field> <cmp-field> <field-name>name</field-name> </cmp-field> <cmp-field> <field-name>description</field-name> </cmp-field> <cmp-field> <field-name>basePrice</field-name> </cmp-field> . ejb-jar..xml : le descripteur de déploiement(1) <?xml version="1. .dtd"> <ejb-jar> <enterprise-beans> <entity> <ejb-name>Product</ejb-name> <home>examples.0"?> <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems.ProductLocal</local> <ejb-class>examples.sun.x</cmp-version> .ProductLocalHome</local-home> <local>examples.//DTD Enterprise JavaBeans 2. Inc..ejb-jar.ProductHome</home> <remote>examples.Product</remote> <local-home>examples.ProductBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>examples.0//EN" "http://java.com/j2ee/dtds/ejb-jar_2_0.

<ejb-ql> <![CDATA[SELECT OBJECT(a) FROM ProductBean AS a WHERE description = ?1]]> </ejb-ql> </query> <query> <query-method> <method-name>findByBasePrice</method-name> <method-params> <method-param>double</method-param> </method-params> </query-method> <ejb-ql> <![CDATA[SELECT OBJECT(a) FROM ProductBean AS a WHERE basePrice = ?1]]> </ejb-ql> </query> ..String</method-param> </method-params> </query-method> . ejb-jar.xml : le descripteur de déploiement(4) .lang..lang..ejb-jar.. .xml : le descripteur de déploiement(3) <query> <query-method> <method-name>findByName</method-name> <method-params> <method-param>java..String</method-param> </method-params> </query-method> <ejb-ql> <![CDATA[SELECT OBJECT(a) FROM ProductBean AS a WHERE name = ?1]]> </ejb-ql> </query> <query> <query-method> <method-name>findByDescription</method-name> <method-params> <method-param>java..

... <query> <query-method> <method-name>findExpensiveProducts</method-name> <method-params> <method-param>double</method-param> </method-params> </query-method> <ejb-ql> <![CDATA[SELECT OBJECT(a) FROM ProductBean AS a WHERE basePrice > ?1]]> </ejb-ql> </query> <query> <query-method> <method-name>findCheapProducts</method-name> <method-params> <method-param>double</method-param> </method-params> </query-method> . <ejb-ql> <![CDATA[SELECT OBJECT(a) FROM ProductBean AS a WHERE basePrice < ?1]]> </ejb-ql> </query> <query> <query-method> <method-name>findAllProducts</method-name> <method-params> </method-params> </query-method> <ejb-ql> <![CDATA[SELECT OBJECT(a) FROM ProductBean AS a WHERE productID IS NOT NULL]]> </ejb-ql> </query> </entity> </enterprise-beans> ..ejb-jar. . ejb-jar...xml : le descripteur de déploiement(6) ..xml : le descripteur de déploiement(5) ..

.xml : le descripteur de déploiement(7) .. wizards…) . il est long ! Mais il est simple ! En plus. <assembly-descriptor> <container-transaction> <method> <ejb-name>Product</ejb-name> <method-intf>Remote</method-intf> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar> Descripteur de déploiement : remarques Ouch. il est souvent généré par des outils (IDE.ejb-jar.

Si la table existe. associer les attributs du bean avec des noms de colonnes… Si la table n'existe pas. il faut indiquer le mapping Objet/Relationnel au container. .*.class).lookup("ProductHome"). Product.*.getProperties()).*.*/ public class ProductClient { public static void main(String[] args) throws Exception { ProductHome home = null. import java..PortableRemoteObject.rmi. En gros.narrow(ctx.rmi.ejb.java (1) package examples. home = (ProductHome) PortableRemoteObject. ProductHome.the factory for Product EJB * Objects */ Context ctx = new InitialContext(System. import javax.naming. Client. le container peut la créer automatiquement.util.Descripteur spécifique Dans le cas où on utilise un SGBD relationnel pour la persistance. import javax. try { /* Get a reference to the Product Home Object . import javax. les IDE proposent le plus souvent des wizards pour vous aider. /** Client test application on a CMP Entity Bean.*. import java.

out.java (3) /* Find all products that cost $200 */ System.Client.hasNext()) { try { Product prod = (Product) PortableRemoteObject.findAllProducts(). "400 Mhz Pentium".println("These products match the name SD-64:").narrow(i.create("123-456-7895". System.println("Finding all products that cost $200"). /* Find a Product.java (2) /* Use the factory to create the Product EJB Object*/ home. 50).println(prod.class)."). while (i.iterator(). home. 200).getDescription()). Product.printStackTrace().class).next(). "SD-64".println("Destroying products. "P5-400".iterator().create("123-456-7892".iterator(). "128 MB SDRAM". home. "SD-128".narrow(i.create("123-456-7894".create("123-456-7890". "P5-450".narrow(i. i = home.class). System. home. Product. } } catch (Exception e) { e. "256 MB SDRAM". "SD-256".out.out. } finally { if (home != null) { System.. Product. while (i. /* Find all the products */ Iterator i = home.create("123-456-7893". "450 Mhz Pentium". 400).out.next().create("123-456-7891". 200).out. while (i.getDescription()). System. "64 MB SDRAM". 300).findByBasePrice(200).next().println(prod. and print out it's description */ Iterator i = home. 100). } Client. "P5-350". home. home.hasNext()) { Product prod = (Product) PortableRemoteObject. .hasNext()) { Product prod = (Product) PortableRemoteObject.findByName("SD-64"). "350 Mhz Pentium".

getProductID(). } } } } } } Client. .startsWith("123")) { prod.Client.java : résultats These products match the name SD-64: 64 MB SDRAM Finding all products that cost $200 USB Speaker System 350 Mhz Pentium 256 MB SDRAM Destroying products..printStackTrace().remove().java (4) if (prod. } } catch (Exception e) { e.

Cycle de vie d'un bean CMP Message-Driven Beans Michel Buffa (buffa@unice.fr). UNSA 2002 .

le client est coincé.Message-Driven Beans Nouveauté EJB 2. Message-Driven Beans : motivation Performance Un client RMI-IIOP attend pendant que le serveur effectue le traitement d'une requête.0. S'il crashe. ou si le réseau crashe. Fiabilité Lorsqu'un client RMI-IIOP parle avec un serveur. comparé à RMI-IIOP. Pas de broadcasting ! RMI-IIOP limite les liaisons 1 client vers 1 serveur . Messaging = moyen de communication léger. ce dernier doit être en train de fonctionner. Pratique dans de nombreux cas. Message-Driven beans = beans accessibles par messaging asynchrone.

IBM MQSeries. Fiorano FioranoMQ. Progress SonicMQ. tolérance aux fautes. … Ces produits fournissent : messages avec garantie de livraison. load-balancing des destinations. Tibco Rendezvous. etc… . BEA Tuxedo/Q. Talarian SmartSockets.Messaging C'est comme le mail ! Ou comme si on avait une troisième personne entre le client et le serveur ! Messaging A cause de ce "troisième homme" les performances ne sont pas toujours au rendez-vous ! Message Oriented Middleware (MOM) est le nom donné aux middlewares qui supportent le messaging. Microsoft MSMQ.

il faut choisir un domaine Domaine = type de messaging Domaines possibles Publish/Subscribe (pub/sub) : n producteurs. n consommateurs (tv) Point To Point (PTP) : n producteurs. pour rendre connecter l'API et les serveurs MOM. Une API pour le développeur.The Java Message Service (JMS) Les serveurs MOM sont pour la plupart propriétaires : pas de portabilité des applications ! JMS = un standard pour normaliser les échanges entre composant et serveur MOM. Un Service Provider Interface (SPI). via les drivers JMS JMS : Messaging Domains Avant de faire du mesaging. 1 consommateur .

Créer un producteur ou un consommateur JMS Utilisés pour écrire ou lire un message. 6. Localiser la destination JMS Il s'agit du canal. Localiser le driver JMS lookup JNDI. Créer une connection JMS obtenir une connection à partir de la connection factory 3. de la chaîne télé ! Normalement. On obtient la destination via JNDI. Envoyer ou recevoir un message JMS : les étapes . Créer une session JMS Il s'agit d'un objet qui va servir à recevoir et envoyer des messages. c'est réglé par le déployeur. 4. On l'obtient à partir de la connection. 5. Le driver est une connection factory 2. On les obtient à partir de la destination ou de la session.JMS : les étapes 1.

public class Client { public static void main (String[] args) throws Exception { // Initialize JNDI Context ctx = new InitialContext(System.*.*.createTopicConnection().JMS : les interfaces JMS : exemple de code (1) import javax. import javax.jms.naming.jms.*. // 2: Use ConnectionFactory to create JMS connection TopicConnection connection = factory. import java.getProperties()).util. // 1: Lookup ConnectionFactory via JNDI TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("javax.TopicConnectionFactory"). .

lookup("testtopic"). // 5: Create a Message Producer TopicPublisher publisher = session. and publish it TextMessage msg = session. Session.AUTO_ACKNOWLEDGE). descripteurs spécialisés.setText("This is a test message.createTextMessage(). msg. // 6: Create a text message. publisher. pooling. // 4: Lookup Destination (topic) via JNDI Topic topic = (Topic) ctx. code simple… .JMS : exemple de code (2) // 3: Use Connection to create session TopicSession session = connection.createPublisher(topic).").publish(msg). } } Intégrer JMS et les EJB Pourquoi créer un nouveau type d'EJB ? Pourquoi ne pas avoir délégué le travail à un objet spécialisé ? Pourquoi ne pas avoir augmenté les caractéristiques des session beans ? Parce que ainsi on peut bénéficier de tous les avantages déjà rencontrés : cycle de vie.createTopicSession( false.

Qu'est-ce qu'un Message-Driven Bean ? Un EJB qui peut recevoir des messages Il consomme des messages depuis les queues ou topics. ObjectMessage. TextMessage. Un MDB n'a pas d'interface Home. Utiliser instanceof au run-time pour connaître le type du message. Les MDB n'ont pas de valeur de retour Ils sont découplés des producteurs de messages. Local Home. . StreamMessage ou MapMessage) Pas de vérification de types à la compilation. Remote ou Local. Les MDB possèdent une seule méthode. faiblement typée : onMessage() Elle accepte un message JMS (BytesMessage. il utilise l'API JMS. envoyés par les clients JMS Qu'est-ce qu'un Message-Driven Bean ? Un client n'accède pas à un MDB via une interface.

Qu'est-ce qu'un Message-Driven Bean ? Pour envoyer une réponse à l'expéditeur : plusieurs design patterns… Les MDB ne renvoient pas d'exceptions au client (mais au container). Dans ce cas. Les MDB sont stateless… Les MDB peuvent être des abonnés durables ou nondurables (durable or nondurable subscribers) à un topic Durable = reçoit tous les messages. le message est rendu persistant et sera délivré lorsque l'abonné sera de nouveau actif. même si l'abonné est inactif. . S'il est durable. Qu'est-ce qu'un Message-Driven Bean ? Le consommateur (celui qui peut les détruire) des messages est en général le Container C'est lui qui choisit d'être durable ou non-durable. Nondurable = messages perdus lorsque abonné inactif. les messages résistent au crash du serveur d'application.

MessageDrivenBean extends EnterpriseBean { public void ejbRemove() throws EJBException. initialiser des attributs… ejbRemove() Libérer les ressources… setMessageDrivenContext(MessageDrivenContext) Appelée avant ejbCreate. } public interface javax. Développer un Message-Driven Bean Méthodes qui doivent être implémentées onMessage(Message) Invoquée à chaque consommation de message Un message par instance de MBD. } La classe d'implémentation doit fournir une méthode ejbCreate() qui renvoit void et qui n'a pas d'arguments. sert à récupèrer le contexte. public void setMessageDrivenContext(MessageDrivenContext ctx) throws EJBException.MessageListener { public void onMessage(Message message). pooling assuré par le container ejbCreate() Récupèrer les références aux ressources. Ne contient que des méthodes liées aux transactions… .jms.ejb.Développer un Message-Driven Bean Les MDBs doivent implémenter public interface javax.

Développer un Message-Driven Bean Un exemple simple Un MDB qui fait du logging. Utile pour débugger…. c'est à dire affiche des messages de textes à l'écran chaque fois qu'il consomme un message. Rappel : pas d'interfaces ! .

.. /** Associates this Bean instance with a particular context. try { String text = tm.. System.*.La classe du bean package examples.*.ejb.err. } catch(JMSException e) { e.getText().err. } } /** Destroys the bean */ public void ejbRemove() { System. MessageListener { protected MessageDrivenContext ctx. /** Sample Message-Driven Bean */ public class LogBean implements MessageDrivenBean. /** Our one business method */ public void onMessage(Message msg) { TextMessage tm = (TextMessage) msg. } .println("Received new message : " + text). import javax.err. import javax. */ public void setMessageDrivenContext(MessageDrivenContext ctx) { this.println("ejbRemove()").ctx = ctx.jms. . } } .println("ejbCreate()").. } /** Initializes the bean */ public void ejbCreate() { System.printStackTrace().

Inc.jms.The type of transaction supported (see Chapter 10) --> <transaction-type>Container</transaction-type> <!-.The nickname for the bean could be used later in DD --> <ejb-name>Log</ejb-name> <!-.Le descripteur de déploiement <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems.Topic</destination-type> </message-driven-destination> </message-driven> </enterprise-beans> </ejb-jar> Question ? Comment sait-on quelle queue ou quel topic de messages le bean consomme ? Cela n'apparaît pas dans le descripteur ! C'est fait exprès pour rendre les MDB portables et réutilisables.LogBean</ejb-class> <!-.//DTD Enterprise JavaBeans 2.Whether I'm listening to a topic or a queue --> <message-driven-destination> <destination-type>javax. you have to define a <message-driven> entry in the deployment descriptor.The fully qualified package name of the bean class --> <ejb-class>examples. L'information se trouve dans le descripteur spécifique .dtd"> <ejb-jar> <enterprise-beans> <!-For each message-driven bean that is located in an ejb-jar file.sun. --> <message-driven> <!-.com/j2ee/dtds/ejb-jar_2_0.0//EN" "http://java.

dtd"> <ejb-jar> <enterprise-beans> <message-driven> <ejb-name>HelloEJBQueue</ejb-name> <message-driven-destination-name>serial://jms/q</message-driven-destination-name> <connection-factory-name>serial://jms/xaqcf</connection-factory-name> <pool> <max-size>20</max-size> <init-size>2</init-size> </pool> </message-driven> <message-driven> <ejb-name>HelloEJBTopic</ejb-name> <message-driven-destination-name>serial://jms/t</message-driven-destination-name> <connection-factory-name>serial://jms/tcf</connection-factory-name> <pool> <max-size>20</max-size> <init-size>2</init-size> </pool> </message-driven> </enterprise-beans> </ejb-jar> Le client (1) import javax.TopicConnectionFactory").jms.*.com/devsupport/appserver/dtds/ejb-jar_2_0-borland.0" encoding="UTF-8"?> <!DOCTYPE ejb-jar PUBLIC "-//Borland Software Corporation//DTD Enterprise JavaBeans 2.jms. // 1: Lookup ConnectionFactory via JNDI TopicConnectionFactory factory = (TopicConnectionFactory) ctx. import java.*.naming. . // 2: Use ConnectionFactory to create JMS connection TopicConnection connection = factory. tiré d'un autre exemple (Borland) <?xml version="1.getProperties()).0//EN" "http://www.util.createTopicConnection().*. import javax. public class Client { public static void main (String[] args) throws Exception { // Initialize JNDI Context ctx = new InitialContext(System.Exemple de descripteur spécifique.lookup("javax.borland.

"). ou on ne peut que faire des statistiques… .AUTO_ACKNOWLEDGE). msg. // 6: Create a text message. La production et la consommation du message sont dans deux transactions séparées… Sécurité.createTextMessage(). Session.createTopicSession( false. d'où qu'ils proviennent. Comparer avec les appels RMI-IIOP pour les session et entity beans. } } Concepts avancés Transactions et MBD.publish(msg).lookup("testtopic"). publisher. and publish it TextMessage msg = session. Les MDB ne reçoivent pas les informations de sécurité du producteur avec le message. // 5: Create a Message Producer TopicPublisher publisher = session.Le client (2) // 3: Use Connection to create session TopicSession session = connection. // 4: Lookup Destination (topic) via JNDI Topic topic = (Topic) ctx. On ne peut pas effectuer les opérations classiques de sécurité sur les EJB. Load-Balancing.setText("This is a test message.createPublisher(topic). Modèle idéal : les messages sont dans une queue et ce sont les MDB qui consomment.

Concepts avancés Consommation dupliquée dans les architectures en clusters : utiliser une queue au lieu d'un topic si on veut que le message ne soit consommé qu'une fois ! Chaque container est un consommateur ! Concepts avancés .

Pièges ! Ordre des messages Le serveur JMS ne garantit pas l'ordre de livraison des messages. L'appel à ejbRemove() n'est pas garanti. En cas de crash. Messages empoisonnés (poison messages) A cause des transactions un message peut ne jamais être consommé Pièges ! Messages empoisonnés (poison messages) A cause des transactions un message peut ne jamais être consommé . comme pour les session beans stateless… A cause du pooling.

public void setMessageDrivenContext(MessageDrivenContext ctx) { this.jms.*.MDB empoisonné ! package examples.ctx = ctx. import javax. Thread. MessageListener { private MessageDrivenContext ctx.printStackTrace(). public class PoisonBean implements MessageDrivenBean.setRollbackOnly(). // Let's sleep a little bit so that we don't see rapid fire re-sends of the message. public void onMessage(Message msg) try { System. } } } . } public void ejbCreate() {} public void ejbRemove() {} .println("Received msg " + msg....ejb.*. MDB empoisonné ! . } catch (Exception e) { e.getJMSMessageID()).sleep(3000). { // We could either throw a system exception here or // manually force a rollback of the transaction. ctx.out. import javax..

non par le container.MDB empoisonné ! Solutions Ne pas lever d'exception. Utiliser des transactions gérées par le bean. Certains serveurs peuvent configurer une "poison message queue" ou posséder un paramètre "nb max retries" … Comment renvoyer des résultats à l'expéditeur du message ? A faire à la main ! Rien n'est prévu ! .

au niveau du serveur JMS.Comment renvoyer des résultats à l'expéditeur du message ? Néanmoins. Comment renvoyer des résultats à l'expéditeur du message ? . des problèmes se posent si le client est lui-même un EJB de type stateful session bean Que se passe-t-il en cas de passivation ? Perte de la connexion à la destination temporaire! Solution : ne pas utiliser d'EJB SSB comme client! Utiliser une Servlet ou un JSP Autre solution : configurer un topic permanent pour les réponses.

fr).QueueRequestor et javax. pas de gestion de transactions… Le futur : invocation de méthode asynchrone Ajouter de la fonctionnalité aux beans Michel Buffa (buffa@unice. UNSA 2002 .Comment renvoyer des résultats à l'expéditeur du message ? D'autres solutions existent… JMS propose deux classes javax.jms.jms.TopicRequestor qui implémentent une pattern simple question/réponse Solution bloquante.

Appel de méthodes business. Utiliser le modèle de sécurité EJB. Appel de create() sur le home object.Dans ce chapitre. nous allons voir Comment appeler un bean depuis un autre bean. Appeler un bean depuis un autre bean La conception de la moindre application implique des beans qui sont clients d'autres beans… Un bean gestionnaire de compte (session) utilise des beans compte bancaires (entity). Utiliser les propriétés d'environnement du bean au runtime. 3. Appel de remove sur le ejb object. etc… On utilise JNDI comme pour n'importe quel client 1. 2. JMS). 4. Lookup du home object de l'EJB cible via JNDI. Comment utiliser les resources factories (JDBC. . Comment utiliser les EJB object handles et EJB home handles.

. .create(.Appeler un bean depuis un autre bean Comment indiquer les paramètres d'initialisation JNDI (driver. Peut néanmoins changer si le serveur JNDI a une configuration bizarre. Le déployeur ne peut pourtant pas changer votre code ! EJB références = dans le descripteur Permet au déployeur de vérifier que tous les beans références par un autre bean sont bien déployés et enregistrés avec les noms JNDI corrects.. Comprendre les références EJB Dans le code précédent.class).rmi. //Look up the home interface Object result =ctx.PortableRemoteObject. etc…) ? Pas besoin.narrow( result.CatalogHome. //Convert the result to the proper type. Recommandé par la spécification EJB.RMI-IIOP style CatalogHome home =(CatalogHome) javax. le container les a déjà initialisés On les récupères via un InitialContext //Obtain the DEFAULT JNDI initial context by calling the //no-argument constructor Context ctx =new InitialContext().).lookup("java:comp/env/ejb/CatalogHome"). la localisation JNDI du bean recherché est java:comp/env/ejb. //Create a bean Catalog c =home.

We will use this below. We use the "Catalog"ejb-name..CatalogHome</home> <!--The Catalog remote interface class --> <remote>examples. --> <session> <ejb-name>Catalog</ejb-name> <home>examples.CatalogHome</home> .Catalog</remote> <!--(Optional)the Catalog ejb-name --> <ejb-link>Catalog</ejb-link> </ejb-ref> </session> </enterprise-beans> . </session> <session> <ejb-name>Pricer</ejb-name> <home>examples. --> <ejb-ref-name>ejb/CatalogHome</ejb-ref-name> <!--Catalog is a Session bean --> <ejb-ref-type>Session</ejb-ref-type> <!--The Catalog home interface class --> <home>examples..This may not correspond to the actual location to which the deployer binds the object via the container tools.Comprendre les références EJB .We declare it so the deployer knows to bind the Catalog home in java:comp/env/ejb/CatalogHome.PricerHome</home> <ejb-ref> <description> This EJB reference says that the Pricing Engine session bean (Pricer)uses the Catalog Engine session bean (Catalog) </description> Comprendre les références EJB <!-The nickname that Pricer uses to look up Catalog. <enterprise-beans> <!-Here..we define our Catalog bean.The deployer may set up some kind of symbolic link to have the nickname point to the real JNDI location..

lookup("java:comp/env/jdbc/ejbPool"). etc…) .sql. //Perform JNDI lookup to obtain resource factory javax.Resources factories (JDBC. URL de la datasource. Resources factories (JDBC. il faut d'abord la localiser //Obtain the initial JNDI context Context initCtx =new InitialContext().sql.DataSource) initCtx. JMS…) La localisation java:comp/env/jdbc/ejbPool Les informations réelles doivent se trouver dans le descripteur (driver JDBC.DataSource ds =(javax. JMS…) Comment accéder à des ressources extérieures à l'EJB ? Sources de données ? JMS driver ? Pour utiliser une resource factory.

On peut passer ces paramètres dans l'application..Whether connections should be shared with other clients in the different transactions --> <res-sharing-scope>Sharable</res-sharing-scope> </resource-ref> Resources factories (JDBC.Resources factories (JDBC.DataSource</res-type> <!-.This element indicates a resource factory reference --> <resource-ref> <description> This is a reference to a JDBC driver used within the Catalog bean. --> <res-auth>Container</res-auth> <!-.The resource factory class --> <res-type>javax. Ou dans le descripteur (c'est donc le container qui va gérer l'authentification) Cas le plus courant ! .The JNDI location that Catalog uses to look up the JDBC driver. JMS…) Remarque sur <res-auth>.</res-auth> L'accès à la datasource peut nécessiter des autorisations (login.CatalogHome</home> <!-.sql. </description> <!-. JMS…) <enterprise-beans> <session> <ejb-name>Catalog</ejb-name> <home>examples.Security for accessing the resource factory. We declare it so the deployer knows to bind the JDBC driver in java:comp/env/jdbc/ejbPool.--> <res-ref-name>jdbc/ejbPool</res-ref-name> <!-. Can either be "Container" or Application". password).

Le modèle de sécurité EJB Deux mesures de sécurité que les clients doivent satisfaire lorsqu'on ajoute la sécurité à un système EJB 1. A l'aide de login/password validés auprès d'une base de données. Le client doit s'authentifier Le client doit être autorisé Le modèle de sécurité EJB 1. seul le banquier peut les accepter. de LDAP. . etc… Une fois authentifié. on lui associe une security identity pour le reste de la session. Par exemple tout le monde peut faire des offres de prêts. Le client doit être autorisé Une fois authentifié. 2. Le client doit s'authentifier Le mécanisme d'authentification vérifie que le client est bien celui qu'il prétend être. il doit avoir la permission d'effectuer les opérations désirées. 2.

simple lookup dans une BD.1. Login/password.Etape 1 : l'authentification Avec EJB 1.0 propose un modèle portable et robuste A l'aide de Java Authentification and Authorization Service (JAAS) : une API J2EE standard. certificats.0 et 1. pas de mécanisme d'authentification portable EJB 2. Présentation de JAAS JAAS est implémentée par le serveur d'application JAAS permet d'utiliser de manière transparente pour le développeur de bean n'importe quel système d'authentification sous-jacent. etc… . LDAP.

Le serveur web fait la vérif à partir d'un password qu'il à lui-même de son côté. 4.htaccess). dans le cas d'un client web peuvent être de 4 types 1.Présentation de JAAS Quelques commentaires Les informations fournies par le client. certains serveurs permettent SSL Form-based authentification : idem sauf que login et password sont saisis dans un formulaire web Digest authentification : hascode calculé à partir de login+password+message HTTP lui-même. 2. 3. Certificate authentification : protocole X509… . Basic authentification : login password en texte (idem .

Architecture JAAS Exemple de code JAAS Cet exemple montre un client qui s'authentifie avant d'appeler la méthode "hello world" d'un bean. une exception est levée . Si le password n'est pas correct.

/* Print the return result from the business logic */ System.*.PortableRemoteObject.login(). import java.doAs(subject. String result =(String)Subject.action).*. import javax.and another that did public/private key certificate authentication.auth. /** Sample configuration class for JAAS user authentication.login.*/ public class PasswordConfig extends Configuration { /** A configuration class must have a no-argument constructor */ public PasswordConfig(){} . loginContext.java (1) package examples.*.getSubject(). import javax.Hashtable.util. } } PasswordConfig.security.we could have a login module that did username/password authentication.security.auth. import javax. This class is useful because it can be rewritten to use different login modules without affecting client code.rmi.out.security. public class HelloClient { public static void main(String [] args))throws Exception { /* Authenticate via JAAS */ LoginContext loginContext =new LoginContext("Hello Client").callback.security.*. /* Retrieve the logged-in subject */ Subject subject =loginContext. For example. import javax.*. /* Perform business logic while impersonating the authenticated subject */ CallHelloWorld action =new CallHelloWorld().println(result).HelloClient. import javax.java package examples.naming. import javax.login.auth.auth.

*. import javax. -The new hashtable is a hashtable of options that our login module will receive.Context. CallbackHandler callbackHandler. new Hashtable()).*.subject =subject.security.auth. The purpose of this class is to actually go out and perform the authentication.auth.*/ AppConfigurationEntry []loginModules = new AppConfigurationEntry [1].spi. /** Initializes us. return loginModules.security.callback. */ public class PasswordLoginModule implements LoginModule { private Subject subject = null.java (2) /** This method chooses the proper login module. import javax.Map sharedState.Our login module would inspect this hashtable and start logging output.REQUIRED. For example. -The "REQUIRED" flag says that we require that this login module succeed for authentication.PasswordConfig.naming.*.auth.LoginModuleControlFlag.auth.util.security.security. import javax. Map options) { this. import java.*/ public void refresh(){} } PasswordLoginModule. */ public AppConfigurationEntry [] getAppConfigurationEntry(String applicationName) { /* Return the one login module we ’ve written.PasswordLoginModule". /** Sample login module that performs password authentication.login.java (1) package examples. */ public void initialize(Subject subject. } .*. import javax.*.We set ourselves to the particular subject which we will later authenticate. AppConfigurationEntry. loginModules[0] = new AppConfigurationEntry("examples.we might define an option that turns debugging on. import javax.which uses username/password authentication. } /** Refresh and reload the Configuration object by readingall of the login configurations again.

weblogic. The intention is that you develop a different LoginModule for each J2EE server. We would then write a special callback handler that knows how to interact with the user. This is our chance to perform additional operations.security.getProperties()).it is 100% hidden from your application code behind the LoginModule.jndi. } } /** This method is called if the overall authentication succeeded (even if this particular login module failed).authenticate(env.we don ’t do anything. BEA has provided us with a helper class that talks JNDI to the Weblogic server.setSecurityPrincipal("guest"). In this case.Environment env = new weblogic. } catch (Exception e){ throw new LoginException(e.populating Subject Note:In a real application.It is called when the client tries to login in. Note that while this code is not portable.toString()).RDBMS. such as a file.auth. @return true if this method executes properly */ public boolean commit()throws LoginException { return true.java (3) env. PasswordLoginModule.subject). Our method implementation contains the vendor-specific way to access our permanent storage of usernames and passwords.Environment(System. Rather.such as prompting the user for a password. } .PasswordLoginModule.*/ public boolean login()throws LoginException { try { /* Authenticate the user ’s credentials.we would not hardcode the username and ^p password. but since we are so simple. env. /* Return that we have successfully authenticated the subject* / return true. */ weblogic.setSecurityCredentials("guest").we would write a reusable LoginModule that would work with any username and password. This could happen if there are other login modules involved with the authentication process. We would then call that callback handler here.java (2) /** This method authenticates the user.Authenticate.or LDAP server.and the server then goes to whatever the currently configured security realm is.jndi.

PasswordLoginModule.java (4)
/** This method is called if the overall authentication failed (even if this particular login module succeeded).This could happen if there are other login modules involved with the authentication process. This is our chance to perform additional operations, but since we are so simple,we don ’t do anything. @return true if this method executes properly */ public boolean abort()throws LoginException { return true; } /** Logout the user. @return true if this method executes properly */ public boolean logout()throws LoginException { return true; } }

CallHelloWorld.java (1)
package examples; import java.security.*; import javax.naming.*; import java.util.Hashtable; import javax.rmi.PortableRemoteObject; /** This is a helper class that knows how to call a "Hello,World!" bean. It does so in a secure manner, automatically propagating the logged in security context to the J2EE server. */ public class CallHelloWorld implements PrivilegedAction { /* This is our one business method. It performs an action securely, and returns application-specific results.*/ public Object run(){ String result ="Error"; try { /* Make a bean */ Context ctx =new InitialContext(System.getProperties()); Object obj =ctx.lookup("HelloHome");

CallHelloWorld.java (2)
HelloHome home =(HelloHome) PortableRemoteObject.narrow(obj,HelloHome.class); Hello hello =home.create(); /* Call a business method,propagating the security context */ result =hello.hello(); } catch (Exception e){ e.printStackTrace(); } /* Return the result to the client */ return result; } }

Etape 2 : l'autorisation
Une fois identifié, le client doit passer un test d'autorisation On force cette étape en définissant la police de sécurité pour le bean (security policies) Deux manière de faire
1.

2.

Par programmation On effectue les tests dans le code du bean… Par autorisation déclarative Le container effectue les tests…

Rôles de sécurité (security roles)
Rôle de sécurité = une collection d'identités pour le client Un client est autorisé à effectuer une opération
Son identité doit être dans le bon rôle de sécurité pour cette opération, Le déployeur de beans a la responsabilité d'associer les identités et les rôles de sécurité après que vous ayez écrit le bean, Grande portabilité et flexibilité.

Autorisation par programmation
Étape 1 : écrire la logique de sécurité
Savoir qui appelle le bean, On obtient l'information via l'objet EJBContext
public interface javax.ejb.EJBContext { ... public java.security.Principal getCallerPrincipal(); public boolean isCallerInRole(String roleName); ... }

Autorisation par programmation
Exemple d'utilisation de isCallerInRole()
public class EmployeeManagementBean implements SessionBean { private SessionContext ctx; ... public void modifyEmployee(String employeeID) throws SecurityException { /* If the caller is not in the ‘administrators ’ security role,throw an exception.*/ if (!ctx.isCallerInRole("administrators")){ throw new SecurityException(...); } // else,allow the administrator to modify the // employee records //... } }

Autorisation par programmation
Exemple d'utilisation de getCallerPrincipal()
import java.security.Principal; ... public class EmployeeManagementBean implements SessionBean { private SessionContext ctx; ... public void modifyEmployee(){ Principal id = ctx.getCallerIdentity(); String name = id.getName(); // Query a database based on the name to determine if the user is // authorized } }

Autorisation par programmation
Étape 2 : décrire les rôles de sécurité abstraits que le bean va utiliser
Par exemple indiquer que le bean a un rôle "administrator", On indique ceci dans le descripteur de déploiement.

Autorisation par programmation
<enterprise-beans> <session> <ejb-name>EmployeeManagement</ejb-name> <home>examples.EmployeeManagementHome</home> ... <!-This declares that our bean code relies on the administrators role;we must declare it here to inform the application assembler and deployer. --> <security-role-ref> <description> This security role should be assigned to the administrators who are responsible for modifying employees. </description> <role-name>administrators</role-name> </security-role-ref> ... </session> ... </enterprise-beans>

... .Autorisation par programmation Étape 3 : associer les rôles de sécurité abstraits avec des rôles concrets (actual) Autre niveau d'indirection.defined below --> <role-link>admins</role-link> </security-role-ref> ...EmployeeManagementHome</home> . </description> <role-name>administrators</role-name> <!-... <security-role-ref> <description> This security role should be assigned to the administrators who are responsible for modifying employees. permet au déployeur de beans de renommer les rôles… Autorisation par programmation .called "admins". </session> <assembly-descriptor> .to a real security-role. <enterprise-beans> <session> <ejb-name>EmployeeManagement</ejb-name> <home>examples.Here we link what we call "administrators"above..

. --> <security-role> <description> This role is for personnel authorized to perform employee administration. </assembly-descriptor> </enterprise-beans> . au déploiement.. </description> <role-name>admins</role-name> </security-role> ...Autorisation par programmation <!-This is an example of a real security role. Le container fait tout le travail ! Étape 1 : déclarer les permissions associées aux méthodes du bean que l'on désire sécuriser Le container génèrera le code qui fera les vérifications nécessaires dans l'EJB home et dans l'EJB object . Autorisation déclarative Tout se passe dans le descripteur.

Exemple de déclaration d'autorisation (2) <!– You can set permissions on a method level..Exemple de déclaration d'autorisation (1) <assembly-descriptor> <!-. .. Example:Allow role "administrators" to call every method on the bean class. --> <method-permission> <role-name>administrators</role-name> <method> <ejb-name>EmployeeManagement</ejb-name> <method-name>*</method-name> </method> </method-permission> .You can set permissions on the entire bean. --> <method-permission> <role-name>managers</role-name> <method> <ejb-name>EmployeeManagement</ejb-name> <method-name>modifySubordinate</method-name> </method> <method> <ejb-name>EmployeeManagement</ejb-name> <method-name>modifySelf</method-name> </method> </method-permission> ... Example: Allow role "managers"to call method "modifySubordinate()"and "modifySelf()".

. --> <exclude-list> <description> We don ’t have a 401k plan... . Example:allow role "employees"to call method "modifySelf(String)"but not modifySelf(Int)" --> <method-permission> <role-name>employees</role-name> <method> <ejb-name>EmployeeManagement</ejb-name> <method-name>modifySelf</method-name> <method-params>String</method-params> </method> </method-permission> Exemple de déclaration d'autorisation (4) <!-This is the list of methods that we don ’t want ANYONE to call.so we don’t support this method. </assembly-descriptor> .Exemple de déclaration d'autorisation (3) <!-. Useful if you receive a bean from someone with methods that you don’t need. </description> <method> <ejb-name>EmployeeManagement</ejb-name> <method-name>modify401kPlan</method-name> <method-params>String</method-params> </method> </exclude-list> .If you have multiple methods with the same name but that take different parameters.you can even set permissions that distinguish between the two..

. </assembly-descriptor> . Déclarer les rôles de sécurité <assembly-descriptor> <security-role> <description> System administrators </description> <role-name>administrators</role-name> </security-role> <security-role> <description> Employees that manage a group </description> <role-name>managers</role-name> </security-role> <security-role> <description> Employees that don ’t manage anyone </description> <role-name>employees</role-name> </security-role> .Autorisation déclarative Étape 2 : déclarer les rôles de sécurité Même méthode que pour les autorisation par programmation… On les déclare et on donne une description (optionnelle) pour le deployeur..

dans la spécification EJB 2.000 francs. Plus facile à maintenir et à ajuster. Le travail du déployeur. on utiliserait tout le temps la méthode déclarative Externalisation de la politique de sécurité. qu'il passe de stub et skeleton. Le client doit-il encore passer les tests de sécurité pour B ? En coulisse. d'appel de méthode en appel de méthode… .0 il manque encore La gestion de la sécurité par instance. le container gère un contexte de sécurité (Security Context). La méthode de A qu'il appelle appelle une méthode d'un bean B. (seul le chef peut manipuler les comptes bien fournis!) Dans ce cas. recourir à la gestion par programmation. pas du développeur ! Malheureusement. Propagation de la sécurité Un client a passé tous les tests de sécurité pour appeler le bean A. Ex : un bean banquier ne peut modifier que des instances de comptes bancaires dont le solde est inférieur à 50.Que choisir ? Déclarative ou par programmation ? Dans un monde idéal.

Propagation de la sécurité <enterprise-beans> <session> <ejb-name>EmployeeManagement</ejb-name> <home>examples. </description> <role-name>admins</role-name> </security-role> .. Ces messages ne contiennent pas d'information liées à la sécurité (credentials) Un MDB ne peut pas non plus propager un contexte de sécurité qui n'existe pas.. .EmployeeManagementHome</home> <security-identity> <run-as> <role-name>admins</role-name> </run-as> </security-identity> </session> <assembly-descriptor> . Ils peuvent néanmoins avoir une identité lorsqu'ils appellent d'autres beans. ils reçoivent des messages.. ni déclarative. ni par programmation Les MDB ne reçoivent pas d'appel de méthode par RMI-IIOP. </assembly-descriptor> </enterprise-beans> Un mot sur les Message-Driven Beans Pas de gestion d'autorisation pour les MDB. <security-role> <description> This role is for personnel authorized to perform employee Administration..

Comprendre les EJB Object Handles Dans certaines applications. puis se reconnecter plus tard en retrouvant le bean dans l'état ! Exemple : un caddy représenté par un session bean stateful… le client décide de se déconnecter… lorsqu'il se reconnecte il veut retrouver son caddy dans l'état ! Comprendre les EJB Object Handles La spécification EJB fournit un outil particulier pour gérer ce genre de situations : l'EJB object handles C'est un proxy vrs un EJB object. . le client d'un bean peut se déconnecter. Longue durée de vie.

and then save it in permanent storage. When we want to use the EJB object again. deserialize // the EJB object handle ObjectInputStream stream =.. ObjectOutputStream stream =.get the EJB object handle from the EJB object..Exemple d'utilisation d'un EJB Object Handle //First.PortableRemoteObject. Variante : les EJB Home Handles Idem..getEJBObject(). // Convert the EJB object handle into an EJB object MyRemoteInterface myEJBObject =(MyRemoteInterface) javax.rmi.... serialize myHandle.ejb. // Resume calling methods again myEJBObject. MyRemoteInterface.Handle myHandle =myEJBObject. Handle myHandle =(Handle) stream.callMethod(). Peu utilisés… . // Next. javax.writeObject(myHandle).readObject(). stream.class).narrow(myHandle.. // time passes. mais pour rendre persistant une référence vers le home object d'un bean.getHandle()..

Gestion des transactions Michel Buffa (buffa@unice.and then save it in permanent storage.class).get the EJB home handle from the home object.ejb.serialize the home handle.When we want to use the home object again. ObjectOutputStream stream =.fr). javax. UNSA 2002 .. // Convert the home object handle into a home object MyHomeInterface myHomeObject =(MyHomeInterface) javax. stream.ejb. javax...rmi. // time passes.readObject(). MyHomeInterface.create().Exemple d'utilisation d'un EJB Home Handle //First.getHomeHandle().HomeHandle homeHandle =(HomeHandle)stream.. //Next.narrow(homeHandle.getHomeObject(). // Resume using the home object myHomeObject..deserialize the home // handle ObjectInputStream stream =.HomeHandle homeHandle =myHomeObject....PortableRemoteObject.writeObject(homeHandle).

bien que composées de plusieurs petites opérations Ex : transfert de compte à compte bancaire : on enlève sur un compte. mais si une d'elles échoue.Gestion de transactions Service clé pour le développement côté serveur. on dépose sur l'autre… Si une des deux opérations échoue. Motivation pour les transactions Opérations atomiques. comme des mises-à-jours dans une base de données… Dans ce chapitre nous présentons le concept de transaction et sa mise en application au sein des EJB. Les transactions sont très utiles lorsqu'on effectue des opérations de persistance. perte de cohérence ! On veut que soit les deux opérations réussissent. on annule le tout et on remet les comptes dans l'état initial ! On dit que les deux opérations forment une seule et même transaction ! . Permet à des applications de fonctionner de manière robuste.

o s'arrête. } try { // Sinon. mais avant. on redépose //l'argent sur le compte 1 return. on arrête. } Qu'en pensez-vous ? Traitement par exceptions Et si on échoue la dernière opération et qu'on arrive pas à remettre l'argent sur le compte 1 ? Et si au lieu d'un traitement simple on a un gros traitement à faire qui se compose de 20 opérations différentes ? Comment on teste tous les cas d'erreur ? . return. on dépose l'argent sur le compte 2 } catch (Exception e){ // Si une erreur est apparue.Traitement par exceptions On peut s'en sortir en gérant des exceptions try { // retirer de l'argent du compte 1 } catch (Exception e){ // Si une erreur est apparue.

Panne réseau ou panne machine Panne réseau ou panne machine Le réseau plante. ou après ? Impossible de savoir Peut-être que le SGBD s'est crashé ? La machine ? La BD est peut-être devenue inconsistante ? Le traitement par Exception est vraiment inacceptable ici. le client reçoit une RMI Remote Exception L'erreur est intervenue avant qu'on enlève l'argent. il n'est pas suffisant ! .

Partage concurrent de données Partage concurrent de données Plusieurs clients consultent et modifient les mêmes données… On ne peut tolérer de perte d'intégrité des données ! .

Un peu de vocabulaire Objet ou composant transactionel Un composant bancaire impliqué dans une transaction. à une queue de message… Implémentent l'interface X/Open XA. Un EJB compte bancaire. un composant . standard de facto pour la gestion de transactions… . Traduire par "toutes les opérations qui la composent…" Les transactions s'accordent avec les pannes machines ou réseau. soit elle échoue. CORBA… Gestionnaire de transaction Celui qui en coulisse gère l'état de la transaction Ressource L'endroit où on lit et écrit les données : un DB.Problèmes résolus par les transactions ! Un transaction est une série d'opérations qui apparaissent sous la forme d'une large opération atomique. Répondent au problèmes du partage de données.NET. une queue de messages. autre… Gestionnaire de ressource Driver d'accès à une BD. Soit la transaction réussit.

réseau) En général. ejbs. Nested transactions ou transactions imbriquées Non supportées par les EJBs pour le moment… . Modèles de transactions Il existe deux modèles 1. corba.Les propriété ACID Atomicité Nombreux acteurs : servlet. DB… Tous votent pour indiquer si la transaction s'est bien passée… Consistance Le système demeure consistent après l'exécution d'une transaction (comptes bancaires ok!) Isolation Empêche les transactions concurrentes de voir des résultats partiels. rmi-iiop. Flat transactions ou transactions à plat Supportées par les EJBs 2. Chaque transaction est isolée des autres. on utilise un fichier de log qui permet de faire des undos pour revenir dans l'état avant le crash. machine. Implémenté par des protocoles de synchronisation bas-niveau sur les BDs… Durabilité Garantit que les mises à jour sur une BD peuvent survivre à un crash (BD.

sinon elle échoue (aborted) En cas de commit. les opérations sont annulées (rolled back). L'application est également prévenue… Flat transactions . les opérations sont validées (permanent changes) En cas d'abort. la transaction est commitée (commited). on effectue des opérations… Si toutes les opérations sont ok.Flat transactions Modèle le plus simple. Après qu'une transaction ait démarré.

2. Puis un billet d'avion de Marseille à Londres. Notre application achète un billet de train de Nice à Marseille. 3. Puis un billet d'avion de Londres à New-York. Transactions imbriquées Cas d'école : on veut faire un tour du monde 1. L'application s'aperçoit qu'il n'y a plus de billet d'avion disponible ce jour-là pour New-York… Tout échoue et on annule toutes les réservations ! . 4. tout est fait en coulisse.Comment s'effectue le rollback ? Tant qu'il n'y a pas de commit. Vous n'avez pas à vous préoccuper de l'état de votre bean… Il sera restauré en cas de rollback. les modifications à une BD ne sont pas permanentes… Dans un contexte de composants.

Si on ne trouve pas de vol pour New-York. on essaiera peut-être de prendre une correspondance par Philadelphie… Transactions imbriquées . une transaction peut inclure une autre transaction.Transactions imbriquées Avec un modèle de transactions imbriquée.

Le container fait tout le travail en coulisse… 3 manières de gérer les transactions 1. du commit et du abort Ex: le banquier . Gestion des transactions par programmation Responsable : le développeur de bean Il décide dans son code du begin. 2. Par programmation. s'il décide de gérer les transactions par programmation. De manière déclarative. demeurera d'un très haut niveau. Simple vote pour un commit ou un abort. 3. De manière initiée par le client.Gestion des transactions avec les EJBs Seul le modèle flat est supporté. Le code que le développeur écrit.

Inc.dtd"> <ejb-jar> <enterprise-beans> <session> <ejb-name>Hello</ejb-name> <home>examples.Hello</remote> <ejb-class>examples.com/dtd/ejb-jar_2_0.HelloHome</home> <remote>examples.sun.//DTD Enterprise JavaBeans 2..0//EN""http://java.Gestion des transactions déclarative Le bean est automatiquement enrôlé (enrolled) dans une transaction… Le container fait le travail… Gestion des transactions déclarative Génial pour le développeur ! <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems. </session> </enterprise-beans> </ejb-jar> .HelloBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> // ou Bean..

mais granularité importante.Transactions initiées par le client Que choisir ? Par programmation : contrôle très fin possible… Déclaratif : super. etc… . Contrôlé par le client N'empêche pas de gérer les transactions dans le bean (par programmation ou de manière déclarative) Ajoute une couche de sécurisation en plus. qui permet de détecter les crashes machine. réseau.

ejbStore() est appelé. Un verrou (lock) est acquis sur la DB. assurant la consistance.Transactions et entity beans Dans une transaction. On a donc les appels à ejbLoad(). Transactions et entity beans Si on contrôlait la transaction dans le bean Démarrer la transaction avant l'appel à ejbLoad() ou au tout début de ejbLoad(). Problème : le client n'appelle jamais directement ejbLoad() ou ejbStore() ! Il passe par l'EJB object Bean-Managed transactions illégales pour les entity beans. aux méthodes métiers et l'appel à ejbStore() qui se trouvent dans la transaction. Seules les transactions gérées par le container sont autorisées ! . on accède à un entity bean : ejbLoad() est appelé : chargement des données de la DB dans le bean. Juste après l'appel du commit de la transaction. Faire le commit à la fin de ejbStore() ou juste après l'appel à ejbStore(). qui met à jour la DB et libère le verrou.

Transactions et Message-Driven Beans Bean-Managed Transactions La transaction commence et se termine après que le message a été reçu par le MDB. On indique dans le descripteur de déploiement les aknowledgement modes pour indiquer au container comment accuser réception… Container-Managed Transactions La réception du message s'inscrit dans la même transaction que les appels de méthodes métier du MDB. Se fait en précisant les attributs de transaction du bean. En cas de problème. Quand exactement. ce n'est pas précisé… . la transaction fait un rollback.Transactions et entity beans Conséquence : un entity bean n'accède pas à la BD à chaque appel de méthode. il se peut qu'une transaction intervient pour chaque appel de méthode. Solution : inclure plusieurs appels de méthodes de l'entity dans une même transaction. Si un entity s'exécute trop lentement. mais à chaque transaction. impliquant des accès BD. Le container envoi accusé de réception (message acknowledgement) Pas de transaction Le container accusera réception après réception.

On choisit Container-Managed Transaction Piège : si un MDB est expéditeur et consommateur du message.Transactions et Message-Driven Beans Que choisir ? Si on décide de ne pas laisser le container gérer les transactions. On peut spécifier des attributs pour le bean entier ou méthode par méthode. on a pas de moyen de conserver le message dans la queue de destination si un problème arrive. car elles impliquent des accès BD. il faut en plus couvrir les méthode de l'interface home. Donc le message ne peut être consommé! Cqfd. Chaque méthode métier doit être traitée (globalement ou individuellement) Pour les entity beans. . Solution : appeler commit() sur l'objet JMS session juste après l'envoi. on précise des attributs de transaction Obligatoire pour chaque bean. le tout intervient dans une même transaction Impossible de terminer ! Le message expédié n'est pas mis dans la queue de destination de manière définitive tant que l'envoi n'est pas commité. On peut préciser les deux… Le plus restrictif gagne. doit figurer dans le descripteur de déploiement. Attributs de transactions gérées par le container Pour chaque bean.

--> <container-transaction> <method> <ejb-name>Employee</ejb-name> <method-name>setName</method-name> <method-param>String</method-param> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> . Can be "NotSupported". --> <container-transaction> <method> <ejb-name>Employee</ejb-name> <method-name>setName</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> --> Exemple de déclaration d'attributs (2) <!-You can even set different transaction attributes on methods with the same name that take different parameters. "Supports".This demonstrates setting a transaction attribute on every method on the bean class. or "Never". "Required".Exemple de déclaration d'attributs (1) <assembly-descriptor> <!-. --> <container-transaction> <method> <ejb-name>Employee</ejb-name> <method-name>*</method-name> </method> <!-. <trans-attribute>Required</trans-attribute> </container-transaction> <!-.You can also set transaction attributes on individual methods. "Mandatory".Transaction attribute. "RequiresNew".

le container crée une nouvelle transaction. La plupart du temps proposé comme valeur par défaut par les IDEs et leurs Wizards/éditeurs de descripteurs… Attribut de transaction : Required Exemple : passage d'une commande Un session bean utilise deux entity beans : un bean carte de crédit et bean commande. une transaction est crée dès que le passage de commande démarre. Si un problème se pose. on envoie la commande. Si une transaction pour ce bean existe. Lors de l'appel au bean Commande. Lors d'un passage de commande. alors le bean la rejoint (join). il rejoindra la transaction en cours. la carte de crédit ne sera pas débitée et la commande ne sera pas passée. si celui-ci est également en mode Required. sinon. puis on débite la carte de crédit. . Idem lors de l'appel au bean Carte de Crédit.Valeur des attributs de transaction Required Le bean est toujours dans une transaction. Si le bean session a comme attribut de transaction Required.

Lorsque la nouvelle transaction se termine (abort ou commit).Attribut de transaction : RequiresNew RequiresNew Le bean est toujours dans une nouvelle transaction. A éviter pour les applications mission-critical ! Dans ce cas. sans qu'une logique externe intervienne. l'ancienne transaction est résumée. elle n'est pas crée. Utile si on veut respecter les propriétés ACID dans l'unité du bean. Si l'exécution du bean intervient dans une transaction existante. . il la rejoint néanmoins. elle est suspendue. choisir Required. Si une transaction existe. Attribut de transaction : Supports Supports Semblable à Required sauf que si une transaction n'existe pas.

. le bean s'exécute.TransactionRequiredLocalException qui est levée… Attribut sûr. Si le client est local. qui oblige le client à inscrire sa logique dans une transaction avant d'appeler le bean.Attribut de transaction : Mandatory Mandatory Une transaction doit exister lorsque le bean est exécuté.ejb. c'est javax.TransactionRequiredException est levée et renvoyée au client. Si une transaction existe lors de l'appel du bean. Si ce n'est pas le cas. Attribut de transaction : NotSupported NotSupported Le Bean ne supporte pas les transactions. puis la transaction est résumée. la transaction est suspendue. javax. Utiliser cet attribut lorsque les propriétés ACID ne sont pas importantes… Exemple : un bean qui fait des statistiques toutes les dix minutes en parcourant une BD.ejb. On tolère que les données lues ne sont peut-être pas à jour… Gain en performance évident.

A utiliser lors du développement d'une logique non transactionnelle. . T2 la nouvelle transaction initiée par le bean appelé. Résumé sur les attributs de transaction Soit T1 une transaction initiée par le client.EJBException est envoyée au client si une transaction existe au moment de l'appel du bean.ejb.rmi. Une exception javax.RemoteException ou javax.Attribut de transaction : Never Never Le Bean ne supporte pas les transactions.

Début et fin d'une transaction Tous les attributs ne s'appliquent pas à tous les beans .

mais plus puissantes. le bean. le container. Le développeur doit utiliser Java Transaction API (JTA) CORBA Object Transaction Service (OTS) Dans une transaction de nombreux partis sont impliqués : le driver de DB. Premier effort pour assurer les transactions dans un système distribué : le service CORBA Object Transaction Service (OTS) OTS = ensemble d'interfaces pour le gestionnaire de transactions. etc… Mortel à utiliser ! .Transactions gérées par programmatiion Plus complexes à manipuler. le gestionnaire de ressources.

commit. Il pourra faire les begin. elle couvre tous les aspects complexes d'OTS. . Java Transaction API (JTA) JTA permet au programmeur de contrôler la gestion de transaction dans une logique métier. JTA s'adresse au développeur d'application (vous) et simplifie grandement la gestion de transactions en contexte distribué. JTA se compose de deux interfaces distinctes. rollback. etc… Il peut utiliser JTA dans des EJB mais aussi dans n'importe quelle application cliente.Java Transaction Service (JTS) Sun Microsystems a encapsulé OTS en deux API distinctes JTS s'adresse aux vendeurs d'outils capables d'assurer un service de transaction.

transaction. public void rollback(). public void setRollbackOnly().transaction.JTA : deux interfaces Une pour les gestionnaires de ressources X/Open XA (hors sujet pour nous) Une pour le programmeur désirant contrôler les transactions : javax.UserTransaction { public void begin(). public int getStatus().UserTransaction public interface javax. } . public void commit().UserTransaction L'interface javax.transaction. public void setTransactionTimeout(int).

public static final int STATUS_ROLLING_BACK. public static final int STATUS_PREPARED. public static final int STATUS_COMMITTED.transaction. public static final int STATUS_COMMITTING.transaction.UserTransaction Constantes de la classe javax.transaction. public static final int STATUS_ROLLEDBACK. public static final int STATUS_NO_TRANSACTION. public static final int STATUS_MARKED_ROLLBACK.Status Constantes renvoyées par getStatus() public interface javax. public static final int STATUS_PREPARING.L'interface javax.Status { public static final int STATUS_ACTIVE. } . public static final int STATUS_UNKNOWN.

balance += amt.Status Comparaison entre les deux méthodes Transaction déclarative /** * Dépose de l'argent sur un compte.Constantes de la classe javax.").out.transaction. } Ne pas oublier de spécifier l'attribut de transaction dans le descripteur . */ public void deposit(double amt) throws AccountException { System.println("deposit(" + amt + ") called.

"). userTran.out.commit().begin()...Comparaison entre les deux méthodes Transaction par programmation public void deposit(double amt) throws AccountException { try { System. sinon on obtient du code-spaghetti ! .transaction. <transaction-type>Container</transaction-type> . userTran. } catch (Exception e) { throw new AccountException("Deposit failed because of " + e.toString()).UserTransaction userTran = ctx. } } Comparaison entre les deux méthodes Transaction par programmation Ne pas oublier de mettre dans le descripteur . balance += amt. Conseil : démarrer et terminer la transaction dans le même méthode.getUserTransaction()..println("deposit(" + amt + ") called.. javax.

// perform business operations userTran. You must set the JNDI Initial Context factory.commit(). */ java.util. /* 2: Get the JNDI initial context */ Context ctx = new InitialContext(env).transaction. See your application server product's documentation for details on their particular JNDI settings. fourni par JTA Via JNDI ! Faire attention à ce que chaque transaction ne dure pas longtemps !!! Piège classique ! Transactions initiées par le client try { /* 1: Set environment up. } catch (Exception e) { // deal with any exceptions.Transactions initiées par le client C'est la dernière des méthodes présentées au début de ce chapitre… Il est nécessaire d'obtenir une référence sur un objet UserTransaction.UserTransaction)ctx. the Provider URL. including ones // indicating an abort. /* 4: Execute the transaction */ userTran. The container is required to make the JTA available at the location java:comp/UserTransaction.begin(). and any login names or passwords necessary to access JNDI. */ userTran = (javax. } ..lookup("java:comp/UserTransaction"). /* 3: Look up the JTA UserTransaction interface via JNDI..Properties env = .

Écrit la nouvelle valeur dans la BD Si chaque instance effectue ces opérations de manière atomique. Chacune 1. Ajoute 10 à la valeur lue. 3. 2. Lit la valeur de X.Isolation de transaction Le "I" de ACID ! L'isolation coûte cher en termes de performances. pas de problèmes ! . Nécessité de pouvoir régler le niveau d'isolation entre transactions concurrentes ! Isolation de transaction Un exemple : deux instances A et B d'un même composant accèdent à une même donnée X dans une BD.

Dans la BD on a X=10. Libère le verrou Gestion de file d'attente… exclusion mutuelle. Chaque composant 1. B lit X. B ajoute 10 à sa copie de X et écrit le résultat dans la BD. ce qui est anormal ! On a perdu le traitement effectué par A ! Isolation de transaction Solution : utiliser un verrou. si on ne prend pas de précaution 1. 3. Par exemple. 2.Isolation de transaction Ceci n'est pas garanti selon le niveau d'isolation choisi. Fait le travail précédent sur X. 4. etc… Tout ceci peut-être réglé avec les EJBs . dans la BD on a X=0. Demande un verrou. 2. A ajoute 10 à X et écrit le résultat dans la BD. A lit X. dans la BD on a X=0. Dans la BD on a X=10. 3.

T2 met à jour cette ligne. Niveau d'isolation avec les EJB Lecture brouillée La transaction T1 modifie une ligne. 3. la transaction T2 lit ensuite cette ligne. Lecture brouillée. T1 a extrait deux fois la même ligne et a vu deux valeurs différentes. . T1 extrait à nouveau la même ligne. T2 a donc vu une ligne qui n'a jamais vraiment existé. Puis T1 effectue une annulation (rollback). 2.Niveau d'isolation avec les EJB Le niveau d'isolation limite la façon dont les transactions multiples et entrelacées interfèrent les unes sur les autres dans une BD multi-utilisateur. Lecture ne pouvant être répétée. 3 types de violations possibles 1. Lecture fantôme. Lecture ne pouvant être répétée T1 extrait une ligne.

Si T1 répète la lecture elle verra des lignes qui n'existaient pas auparavant. Ces lignes sont appelées des lignes fantômes. Niveau d'isolation avec les EJB Attribut Uncommited Commited Syntaxe TRANSACTION_READ_UNCOMMITED TRANSACTION_READ_COMMITED Description Autorise l'ensemble des trois violations Autorise les lectures ne pouvant être répétées et les lignes fantômes. n'autorise pas les lectures brouillées Autorise les lignes fantômes mais pas les deux autres violations N'autorise aucune des trois violations Repeatable TRANSACTION_REPEATABLE_READ Serialisable TRANSACTION_SERIALIZABLE .Niveau d'isolation avec les EJB Lecture fantôme T1 lit quelques lignes satisfaisant certaines conditions de recherche. T2 insère plusieurs lignes satisfaisant ces mêmes conditions de recherche.

les relire au cours d'une même transaction. On veut lire des données consistances. Lisent un snapshot des données commitées… Niveau d'isolation par défaut de la plupart des BD (Oracle…) Quel niveau utiliser Repeatable Lorsqu'on veut pouvoir lire et modifier des lignes. Serialisable Pour les applications mission-critical qui nécessitent un niveau d'isolation absolu. Performant mais dangereux ! A éviter pour les applications mission-critical ! Commited Utile pour les applications qui produisent des rapports sur une base de donnée. sans perte de consistance. mêmes si pendant qu'on les lisait quelqu'un était en train de les modifier.Quel niveau utiliser Uncommited Uniquement si on est sûr qu'une transaction ne pourra être mise en concurrence avec une autre. ACID 100% ! Attention .les performances se dégradent à vitesse grand V avec ce mode ! .

Comment spécifier ces niveaux ? Transactions gérées par le bean Appel de java. Problèmes de portabilité ! Impossibilité de spécifier le niveau d'isolation ??? .Connection.. ou via les outils de configuration de la DB ou du container..SetTransactionIsolation(.). Transactions gérées par le container Non. on ne peut pas spécifier le niveau d'isolation dans le descripteur ! On le fera via le driver JDBC.sql.

nous avons vu comment spécifier le type de gestion de transaction. on peut envoyer une Exception au client… On veut également être tenu au courant de ce qu'il se passe pendant l'exécution d'une transaction. Stratégie pessimiste Tout peut foirer. 2. espère que tout va bien se passe. Stratégie optimiste Peu de chance que ça foire. Nous avons vu les niveaux d'isolations. gérée par le bean ou le container. Mais que faire en cas de rollback par exemple On ne peut pas re-essayer indéfiniment d'exécuter une transaction. on fait notre travail. Que faire dans le code EJB ??? Ok. puis on libère le verrou.Deux stratégies Lorsqu'on veut gérer les transactions. si la BD détecte une collision. on prend donc un verrou lors des accès BD. Néanmoins. on doit toujours choisir entre deux stratégies 1. que l'on spécifie la plupart du temps via les pilotes JDBC. on fait un rollback de la transaction. .

ejb. il faut prévoir la possibilité de restaurer un état correct. public void afterCompletion(boolean). on risque d'avoir un état incorrect (celui qui a provoqué l'échec de la transaction). Lors du design d'un bean. si on envoie une Exception au client.SessionSynchronization public interface javax.Que faire dans le code EJB ??? En cas de rollback. Que faire dans le code EJB ??? L'EJB peut implementer une interface optionnelle javax.ejb.SessionSynchronization { public void afterBegin(). Il peut néanmoins vous aider à réaliser cette tâche. que faire de l'état du bean ? Si le bean est stateful. Le container ne peut le faire pour vous car le traitement est en général spécifique à l'application. } Uniquement pour les session beans stateful . public void beforeCompletion().

val=val. } public void afterBegin() { oldVal = val.oldVal=val. public void ejbCreate(int val) { this.} public void beforeCompletion() {} public void afterCompletion(boolean b) { if (b == false) val = oldVal. UNSA 2002 .fr). public int oldVal. } void ejbRemove() {} void ejbActivate() {} void ejbPassivate() {} void setSessionContext(SessionContext ctx) {} Relations avec beans BMP et CMP Michel Buffa (buffa@unice. } public public public public public } int count() { return ++val. SessionSynchronization { public int val.Que faire dans le code EJB ??? Le container appelle afterCompletion() que la transaction se soit terminée par un commit ou par un abort Le paramètre de la méthode nous signale dans quel cas on se trouve public class CountBean implements SessionBean. this.

1-n. Direction des relations (bi-directionnelles. circulaires. Relations récursives. via des Collections. Intégrité référentielle. lazyload. Comment gérer tout ça en BMP et en CMP ! . unidirectionnelles). Agrégation vs composition et destructions en cascade. agressive-load.On complique un peu l'étude des entity beans ! Les entity beans représentant des donnés dans une BD. Accéder aux relations depuis un code client. n-n…). il est logique d'avoir envie de s'occuper de gérer des relations Exemples Une commande et des lignes de commande Une personne et une adresse Un cours et les élèves qui suivent ce cours Un livre et ses auteurs Nous allons voir comment spécifier ces relations dans notre modèle EJB Concepts abordés Cardinalité (1-1.

define enterprise beans ....Différence entre BMP et CMP pour les relations En BMP il faut tout faire à la main public class OrderBean implements EntityBean { // 1 . </enterprise-beans> <relationships> ...méthodes get/set // 3 ..attributs // 2 ... </relationships> </ejb-jar> Le container génère le code pour vous ! .code pour la gestion des relations dans les // } méthodes ejbXXX Différence entre BMP et CMP pour les relations En CMP il faut tout faire dans le descripteur <ejb-jar> <enterprise-beans> . define EJB relationships .

Cardinalité La cardinalité indique combien d'instances vont intervenir de chaque côté d'une relation One-to-One (1:1) Un employé a une adresse… One-to-Many (1:N) Un PDG et ses employés… Many-to-Many (M:N) Des étudiants suivent des cours… Cardinalité .

findByPrimaryKey(). public void ejbLoad() { // 1: SQL SELECT Order.Relations 1:1 Représentée typiquement par une clé étrangère dans une BD Ex : une commande et un colis Relations 1:1 en BMP public class OrderBean implements EntityBean { private String orderPK. } } This also stores the Shipment foreign key. . // EJB local object stub public Shipment getShipment() { return shipment. // 2: JNDI lookup of ShipmentHome // 3: Call ShipmentHome. } public void setShipment(Shipment s) { this. private Shipment shipment. passing in the shipment the foreign key } public void ejbStore() { // 1: Call shipment.} ... private String orderName.shipment = s. This also retrieves the shipment foreign key.getPrimaryKey() to retrieve the Shipment foreign key // 2: SQL UPDATE Order.

public abstract void setShipment(Shipment s). public void ejbLoad() {} public void ejbStore() {} } // Empty // Empty Tout se passe dans le descripteur ! Relations 1:1 en CMP <ejb-jar> <enterprise-beans> . ...Relations 1:1 en CMP public abstract class OrderBean implements EntityBean { // Pas d'attributs public abstract Shipment getShipment(). </enterprise-beans> <relationships> <!– Ceci déclare une relation --> <ejb-relation> <!– Le nom donné à cette relation --> <ejb-relation-name>Order-Shipment</ejb-relation-name> <!– Ceci déclare la première moitié de la relation (Order) --> <ejb-relationship-role> <!– Le nom donné à cette partie de la relation --> <ejb-relationship-role-name>order-spawns-shipment</ejb-relationship-role-name> <!– sa cardinalité --> <multiplicity>One</multiplicity> <!– Le nom du bean correspondant à cette moitié de la relation <role-source><ejb-name>Order</ejb-name></role-source> --> ...

That is the purpose of this element. --> <cmr-field><cmr-field-name>shipment</cmr-field-name></cmr-field> </ejb-relationship-role> <!– Fin de la première moitié de la relation !!!> getShipment() becomes shipment. and with a slight change in capitalization.This declares the 2nd half of the relationship (the Shipment side) --> <ejb-relationship-role> <ejb-relationship-role-name> shipment-fulfills-order </ejb-relationship-role-name> <multiplicity>One</multiplicity> <role-source><ejb-name>Shipment</ejb-name></role-source> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar> . but without the get/set. so that the container can generate the appropriate scaffolding code when subclassing our bean. We need to tell the container which get/set method corresponds to this relationship.Relations 1:1 en CMP <!-.Recall that a CMP entity bean has an abstract get/set method for the relationship. The value of the CMR field should be the name of your get/set method. which is called the container-managed relationship (CMR) field. Relations 1:1 en CMP <!-.

Relations 1:N Exemple : une entreprise a plusieurs employés Relations 1:N Exemple : une entreprise a plusieurs employés Solution plus propre (éviter les BLOBs!) .

public void ejbLoad() { // 1: SQL SELECT Company // 2: JNDI lookup de EmployeeHome // 3: Appel de EmployeeHome.. // Vector d'EJB object stubs public Collection getEmployees() { return employees. pas le bean Company C'est pourquoi ejbLoad() appelle un finder de la classe Employee. mais il aurait fallu encore refaire une série de requêtes SQL pour obtenir les références vers les objets distants… .findByCompany(companyPK). } public void setEmployees(Collection e) { this.} . private String companyName. private Vector employees..Relations 1:N avec BMP. exemple public class CompanyBean implements EntityBean { private String companyPK. qui renvoie une collection de stubs vers les employés qui appartiennent à la compagnie recherchée… On aurait pu en un seul ordre SQL récupérer toutes les clés étrangères des employés. génère un second ordre SQL } public void ejbStore() { // 2: SQL UPDATE Company } Relations 1:N avec BMP Le bean Employee a accès à la clé étrangère.employees = e.

</enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Company-Employees</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Company-Employs-Employees </ejb-relationship-role-name> <multiplicity>One</multiplicity> <role-source><ejb-name>Company</ejb-name></role-source> .. exemple (2) <ejb-jar> <enterprise-beans> . . exemple (1) public abstract class CompanyBean implements EntityBean { // pas d'attributs public abstract Collection getEmployees()... public void ejbLoad() {} public void ejbStore() {} } // Empty // Empty Relations 1:N avec CMP. public abstract void setEmployees(Collection employees)..Relations 1:N avec CMP.

Relations 1:N avec CMP. ejbLoad() pour la partie "1" de la relation. 2.util.util. Appel à une méthode finder pour la partie "N" de la relation. si le container est bon. --> <cmr-field> <cmr-field-name>lineItems</cmr-field-name> <cmr-field-type>java. En CMP. How do you choose between a Collection and a Set? A Collection can contain duplicates. bean's get/set methods. . you can either use a java.util.Collection</cmr-field-type> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> Employees-WorkAt-Company </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <role-source><ejb-name>Employee</ejb-name></role-source> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar> This needs to match up to your Relations 1:N avec CMP. We need to identify which one we're using. whereas a Set cannot.When you have a relationship with more than one object.Collection or a java.Set. Granularité à l'échelle du bean Il peut en une seule requête charger les deux parties de la relation. remarques Les relations 1:N sont souvent bien plus performantes en CMP qu'en BMP En BMP deux étapes sont nécessaires 1. exemple (3) <!-.

Relations M:N Un étudiant suit plusieurs cours. choix de conception Deux possibilités lorsqu'on modélise cette relation avec des EJBs 1. on peut utiliser simplement deux EJB. 2. etc… Cet EJB possèdera deux relations 1:N vers le bean Student et le vers le bean Course Si on a rien besoin de plus à part la relation. un cours a plusieurs étudiants inscrits Table de jointure nécessaire. On veut peut-être mémoriser la date où un étudiant s'est inscrit. chacun ayant un attribut correspondant à une Collection de l'autre EJB… . Utiliser un troisième EJB pour modéliser la table de jointure. Relations M:N.

Course.student = s. // EJB local object stub // EJB local object stub public Course getCourse() { return course.} public Student getStudent() { return student. CourseHome // 3: Call findByPrimaryKey() on both the Student and Course homes. public void ejbLoad() } { // SQL SELECT Course } public void ejbStore() { // SQL UPDATE Course } { // SQL SELECT Student } public void ejbStore() { // SQL UPDATE Student } Relations M:N. private String courseName. This loads both the Enrollment plus the foreign keys to Student // 2: JNDI lookup of StudentHome. } public void setCourse(Course c) { this. private String studentName. private Student student. avec un troisième EJB.. . exemple en BMP (1) En BMP public class StudentBean implements EntityBean { private String studentPK. public void ejbLoad() { // 1: SQL SELECT Enrollment.course = c.. // and Course. . passing the foreign keys } public void ejbStore() { // 1: Call getPrimaryKey() on Student. private Course course.Relations M:N. public void ejbLoad() } public class CourseBean implements EntityBean { private String coursePK.. // 2: SQL UPDATE Enrollment } } This gives us our foreign keys. ... avec un troisième EJB. } .. exemple en BMP (2) public class EnrollmentBean implements EntityBean { private String enrollmentPK. } public void setStudent(Student s) { this.

public void ejbLoad() {} public void ejbStore() {} } // Vide // Vide . public abstract void setCourse(Course c).Relations M:N.. public abstract void setStudent(Student s). exemple en CMP (1) En CMP public abstract class StudentBean implements EntityBean { // Pas d'attributs public void ejbLoad() {} public void ejbStore() {} } // Vide // Vide public abstract class CourseBean implements EntityBean { // Pas d'attributs public void ejbLoad() {} public void ejbStore() {} } // Vide // Vide Relations M:N.. public abstract Student getStudent(). avec un troisième EJB. . exemple en CMP (2) public abstract class EnrollmentBean implements EntityBean { // Pas d'attributs public abstract Course getCourse(). avec un troisième EJB.

Relations M:N.. exemple en CMP (4) <ejb-relationship-role> <ejb-relationship-role-name> Student-Has-Enrollments </ejb-relationship-role-name> <multiplicity>One</multiplicity> <role-source><ejb-name>Student</ejb-name></role-source> </ejb-relationship-role> </ejb-relation> <ejb-relation> <ejb-relation-name>Enrollment-Course</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Enrollments-AreRegistrationsFor-Course </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <role-source><ejb-name>Enrollment</ejb-name></role-source> <cmr-field><cmr-field-name>course</cmr-field-name></cmr-field> </ejb-relationship-role> .. avec un troisième EJB. exemple en CMP (3) <ejb-jar> <enterprise-beans> . avec un troisième EJB. </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Enrollment-Student</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Enrollments-AreRegisteredBy-Student </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <role-source><ejb-name>Enrollment</ejb-name></role-source> <cmr-field><cmr-field-name>student</cmr-field-name></cmr-field> </ejb-relationship-role> Relations M:N.

private Vector courses..courses = c. // EJB object stubs public Collection getCourses() { return courses. avec un troisième EJB. public void ejbLoad() { // 1: SQL SELECT Student // 2: JNDI lookup of CourseHome // 3: Call CourseHome. exemple (1) public class StudentBean implements EntityBean { private String studentPK.} . private String name. } public void setCourses(Collection c) { this. exemple en CMP (5) <ejb-relationship-role> <ejb-relationship-role-name> Course-Has-Enrollments </ejb-relationship-role-name> <multiplicity>One</multiplicity> <role-source><ejb-name>Course</ejb-name></role-source> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar> Vraie relation M:N avec BMP.Relations M:N..findByStudent(studentPK) } public void ejbStore() { // SQL UPDATE Student } .

.Vraie relation M:N avec BMP. private String name. public abstract void setCourses(Collection courses). public void ejbLoad() { // 1: SQL SELECT Course // 2: JNDI lookup of StudentHome // 3: Call StudentHome. public abstract void setStudents(Collection students). public void ejbLoad() {} public void ejbStore() {} } public abstract class CourseBean implements EntityBean { // Pas d'attributs public abstract Collection getStudents(). . } public void setStudents(Collection s) { this.students = s. // EJB object stubs public Collection getStudents() { return students. . private Vector students. public void ejbLoad() {} public void ejbStore() {} } // Vide // Vide // Empty // Empty ..} . exemple (2) public class Course implements EntityBean { private String coursePK.findByCourse(coursePK) } public void ejbStore() { // SQL UPDATE Course } Vraie relation M:N avec CMP. exemple (1) public abstract class StudentBean implements EntityBean { // Pas d'attributs public abstract Collection getCourses().....

util.Collection</cmr-field-type> </cmr-field> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar> ...Vraie relation M:N avec CMP.util.Collection</cmr-field-type> </cmr-field> </ejb-relationship-role> . Vraie relation M:N avec CMP.. exemple (2) <ejb-jar> <enterprise-beans> .. exemple (3) <ejb-relationship-role> <ejb-relationship-role-name> Courses-HaveEnrolled-Students </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <role-source><ejb-name>Course</ejb-name></role-source> <cmr-field> <cmr-field-name>students</cmr-field-name> <cmr-field-type>java. </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Student-Course</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Students-EnrollIn-Courses </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <role-source><ejb-name>Student</ejb-name></role-source> <cmr-field> <cmr-field-name>courses</cmr-field-name> <cmr-field-type>java.

public Shipment getShipment() { return shipment..Direction des relations (directionality) Unidirectionnelle On ne peut aller que du bean A vers le bean B Bidirectionnelle On peut aller du bean A vers le bean B et inversement Implémenter une relation bidirectionnelle en BMP. // EJB local object stub. private String shipmentName.. must be stored/loaded private Shipment shipment. } . public Order getOrder() { return order.order = o.. } public void setShipment(Shipment s) { this. private String orderName. } .shipment = s. exemple public class OrderBean implements EntityBean { private String orderPK. } public void setOrder(Order o) { this. } public class ShipmentBean implements EntityBean { private String shipmentPK.. // EJB local object stub. } . must be stored/loaded private Order order.

.shipment = s. private String orderName. } public class ShipmentBean implements EntityBean { private String shipmentPK. exemple public class OrderBean implements EntityBean { private String orderPK.. } Implémenter une relation bidirectionnelle en CMP. public abstract void setShipment(Shipment s). public abstract void setOrder(Order o)... } public void setShipment(Shipment s) { this. exemple (1) public abstract class OrderBean implements EntityBean { // no fields public abstract Shipment getShipment()... no Order get/set method . // No Order stub. must be stored/loaded private Shipment shipment. // EJB local object stub. . public void ejbLoad() {} public void ejbStore() {} } public abstract class ShipmentBean implements EntityBean { // no fields public abstract Order getOrder(). } ..Implémenter une relation unidirectionnelle en BMP. public Shipment getShipment() { return shipment.. public void ejbLoad() {} public void ejbStore() {} } // Empty // Empty // Empty // Empty . private String shipmentName..

.. </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Order-Shipment</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> order-spawns-shipment </ejb-relationship-role-name> <multiplicity>One</multiplicity> <role-source><ejb-name>Order</ejb-name></role-source> <cmr-field><cmr-field-name>shipment</cmr-field-name></cmr-field> </ejb-relationship-role> Implémenter une relation bidirectionnelle en CMP. exemple (2) <ejb-jar> <enterprise-beans> .Implémenter une relation bidirectionnelle en CMP. exemple (3) <ejb-relationship-role> <ejb-relationship-role-name> shipment-fulfills-order </ejb-relationship-role-name> <multiplicity>One</multiplicity> <role-source><ejb-name>Shipment</ejb-name></role-source> <cmr-field><cmr-field-name>order</cmr-field-name></cmr-field> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar> .

La directionalité et le modèle de données dans la DB La directionalité peut ne pas correspondre à celle du modèle de données dans la DB Schéma normalisé Schéma dénormalisé Relations et interfaces locales On ne le répètera jamais assez. les entity beans sont prévus pour être accédés via leurs interfaces locales Pour des raisons de performance évidentes. Sans doute pas la même que celle utilisé par le container. Nécessité de faire un cast CORBA/II-OP. On peut néanmoins faire des tests unitaires depuis un client remote… mais ! Si un client fait un accès remote via un getXXX() à un champs correspondant à une relation Il reçoit une Collection. très cher (instruction narrow…) .

Tant qu'on ne demande pas quels cours il suit. Second critère : si le schéma relationnel existe.Choisir la directionalité ? Premier critère : la logique de votre application. . Lazy-loading On ne charge les beans en relation que lorsqu'on essaie d'accéder à l'attribut qui illustre la relation. Cas de la Commande et des Colis plus tôt dans ce chapitre. Dans le ejbLoad() on appelle des finders… Peut provoquer un énorme processus de chargement si le graphe de relations est grand. s'adapter au mieux pour éviter de mauvaises performances. on charge aussi tous les beans avec lesquels il a une relation. le bean Etudiant n'appelle pas de méthode finder sur le bean Cours. Lazy-loading des relations Agressive-loading Lorsqu'on charge un bean.

Tous les containers ne supportent pas le lazyloading Nombreuses options chez l'un ou chez l'autre vendeur. loading the shipment foreign key // 2: Set shipmentFK field to the loaded key } public Shipment getShipment() { // 1: JNDI lookup of ShipmentHome // 2: Call ShipmentHome.Lazy-loading des relations avec BMP public class OrderBean implements EntityBean { private String orderPK. Se configure dans le descripteur propriétaire..findByPrimaryKey(shipmentFK) return shipment. le container fait le travail en coulisse. // EJB local object stub public void ejbLoad() { // 1: SQL SELECT Order. } Lazy-loading des relations avec CMP Pas besoin de s'en occuper. Élément-clé dans le choix d'un container.. } . . private String shipmentFK. private String orderName. // Foreign key to shipment private Shipment shipment.

Relation par Composition Le bean se compose d'un autre bean. Destructions en cascade avec BMP public class OrderBean implements EntityBean { private String orderPK.. Par exemple. lorsqu'on supprime un étudiant on ne supprime pas les cours qu'il suit. private Shipment shipment. } public void setShipment(Shipment s) { this.shipment = s.Agrégation vs Composition et destructions en cascade Relation par Agrégation Le bean utilise un autre bean Conséquence : si le bean A utilise le bean B. Par exemple. Et vice-versa. une commande se compose de lignes de commande… Si on détruit la commande on détruit aussi les lignes correspondantes. public void ejbRemove() { // 1: SQL DELETE Order // 2: shipment. Ce type de relation implique des destructions en cascade. // EJB local object stub public Shipment getShipment() { return shipment.. } } . lorsqu'on détruit A on ne détruit pas B.} .remove().. private String orderName.

on peut aussi indiquer la requête qui permet de remplir le champs associé à la relation.. </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Order-Shipment</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> order-spawns-shipment </ejb-relationship-role-name> <multiplicity>One</multiplicity> <role-source><ejb-name>Order</ejb-name></role-source> <cmr-field><cmr-field-name>shipment</cmr-field-name></cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> shipment-fulfills-order </ejb-relationship-role-name> <multiplicity>One</multiplicity> <cascade-delete/> <role-source><ejb-name>Shipment</ejb-name></role-source> <cmr-field><cmr-field-name>order</cmr-field-name></cmr-field> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar> Relations et EJB-QL Lorsqu'on définit une relation en CMP.. l'opérateur "." Pas besoin de connaître le nom des tables.customer FROM Order o Renvoie tous les clients qui ont placé une commande Principale différence avec SQL.Destructions en cascade avec CMP <ejb-jar> <enterprise-beans> . On fait ceci à l'aide d'EJB-QL SELECT o. ni le nom des colonnes… .

address.Relations et EJB-QL On peut aller plus loin… SELECT o.homePhoneNumber FROM Order o On se promène le long des relations… Relations récursives Relation vers un bean de la même classe Exemple : Employé/Manager Rien de particulier.customer. ces relations sont implémentées exactement comme les relations non récursives… .

Attention si relations circulaires ! Supprimer une des relations (!!!) si le modèle de conception le permet. Utiliser le lazy-loading et ne pas faire de destruction en cascade.Relations circulaires Similaire au relations récursives sauf qu'elles impliquent plusieurs types de beans Ex : un employé travaille dans une division. une workstation est allouée à un employé… Ce type de relation. 2. 4. en cas de agressive-loading peut mener à une boucle sans fin… Même problème avec les destructions en cascade… Relations circulaires Plusieurs stratégies sont possibles 1. une division possède plusieurs ordinateurs (workstation). . si le modèle de conception le permet. Les meilleurs moteurs CMP détectent les relations circulaires et vous permettent de traiter le problème avant le runtime. 5. Supprimer la bidirectionnalité d'une des relations pour briser le cercle. 3. Certains containers proposent d'optimiser le chargement d'un bean en chargeant toutes ses relations en cascade dans le ejbLoad().

Le SGBD n'est plus aussi sollicité. il faut vérifier qu'il est bien supprimé partout où on a une relation avec lui. Problème classique dans les SGBDs Résolus à l'aide de triggers. le container fait le travail tout seul ! . Division. Intégrité référentielle Gérer l'intégrité dans le SGBD est intéressant si la BD est attaquée par d'autres applications que les EJBs… Autre approche : gérer l'intégrité dans les EJBs Solution plus propre. etc… a des relations avec un bean Employé Si on supprime un employé. Ces procédures effectuent la vérification d'intégrité. Avec BMP il faudra gérer le tout à la main… Avec CMP.Intégrité référentielle Un bean Compagnie. On peut aussi utiliser des procédures stockées via JDBC. Ils se déclenchent sitôt qu'une perte d'intégrité risque d'arriver et effectuent les opérations nécessaires.

mais comment un client peut-il changer une des relations parmi les "N" ? . les relations "1:N" impliquent les Collections. Comment mettre à jour les relations ? Problème résolu par les transactions !!! Relations.Intégrité référentielle Et dans un contexte distribué ? Plusieurs serveurs d'application avec le même composant peuvent accèder à des données sur le même SGBD. intégrité référentielle et code client Ok.

public abstract void setEmployees(Collection employees).getEmployees().findByPrimaryKey("The Middleware Company").narrow( ctx.lookup("CompanyHome").. intégrité référentielle et code client. CompanyHome companyHome = (CompanyHome) PortableRemoteObject.class). exemple (1) public abstract class CompanyBean implements EntityBean { // pas d'attributs public abstract Collection getEmployees(). Collection employees = company.narrow( ctx.lookup("EmployeeHome"). // Find a company Company company = companyHome . EmployeeHome employeeHome = (Employee) PortableRemoteObject.add(employeeA). // Add the employee to the company... EmployeeHome. public void ejbLoad() {} public void ejbStore() {} } // vide // vide Relations.class).Relations. .. CompanyHome. // Make a new employee Employee employeeA = employeeHome. intégrité référentielle et code client.This demonstrates the add() Collection API method employees. exemple (1) // Lookup local home objects Context ctx = new InitialContext(. … .create("Ed Roman").).

println(emp. // This demonstrates the remove() Collection API employees.getName()). while (i. la Collection implémentée parle container n'est pas celle du JDK standard ! Elle préserve l'intégrité : .next().iterator(). exemple (2) // Look at each employee in the company. remarques On manipule la même collection dans le bean client et le bean serveur car on accède à un objet local Attention si appels remote. // This demonstrates using iterators to loop through collections Iterator i = employees.Relations. System. } // Remove the employee from the company.hasNext()) { Employee emp = (Employee) i.out. Relations. intégrité référentielle et code client. intégrité référentielle et code client.remove(employeeA).

Relations. intégrité référentielle et code client.util. remarques Attention avec les iterators et les relations Si vous voulez supprimer une relation dans un iterator.remove() Sinon ça casse l'itérateur ! Résumé… . utiliser uniquement : java.Iterator.

les écrire. Le plus souvent. les lire. Mais aussi devenir effroyablement complexe ! . les modifier. ces données sont dans un SGBD.fr).Bonnes pratiques de persistance Michel Buffa (buffa@unice. UNSA 2002 On manipule des données persistantes Application moderne = manipuler des données. Lorsqu'on développe une application basée sur les EJB. la gestion de la persistance peut être aussi simple que mapper un EJB sur une table.

Il appelle ejbLoad(). Choisir entre BMP et CMP. ejbStore() dans votre dos… Perte de contrôle parfois déroutante : éduquer les développeurs ! . Approche .Dans ce chapitre… Quand utiliser des entity beans. Quelques design patterns… Quand utilise des entity beans Utiliser simplement des sessions beans + JDBC ? Pourquoi pas ? Contrôle total via JDBC.NET Utiliser des entity beans BMP ou CMP Le container fait une partie du travail (BMP) ou la totalité (CMP).

Similaire à un passage par référence. Lorsqu'on appelle un entity bean. les résultats sont passés par valeur. et y accèdent via leur interface locale. il tourne dans le même container que le bean serveur ! CONCLUSION : utiliser des sessions beans comme front-end pour les clients finaux ! Sérialisent les résultats finaux vers le client. Est-ce plus avantageux pour un session bean de recevoir des résultats par référence ? OUI. sérialisés. Analogie avec le passage de paramètres Réfléchissez… Est-ce plus avantageux pour un client normal de recevoir des résultats distants par référence NON ! Il vaut mieux les recevoir par valeur.Analogie avec le passage de paramètres Lorsqu'on appelle un session bean. Les clients des sessions peuvent être des servlets ou une application classique. La plupart des temps les session beans sont clients des entity beans. . on récupère des stubs sur les objets résultats.

on cachera les 1000 livres les plus demandés chez Amazon.com ! Cache Mais inutile de cacher des données peu partagées Données personnelles… Il est très intéressant d'utiliser des entity beans car souvent les données sont partagées et sont plus souvent lues que modifiées. .Cache Les sessions beans ne représentent pas des données. Les données manipulées ne durent que le temps de la session. les entity beans peuvent être cachés à travers plusieurs transactions Dans le descripteur de déploiement spécifique… Par exemple. D'un autre côté. et ne peuvent donc pas être cachées.

Super pour prototyper. Le container peut résoudre les relations en un seul. si on veut on peut toujours passer en BMP par la suite… Performances : CMP Bien réglés. mais le plus souvent ils sont générés par des wizards. gros ordre SQL. RAD. les beans CMP sont bien plus performants que les BMP. On peut néanmoins optimiser les BMP avec la pattern Fat Key .Un bon schéma relationnel Parfois changer deux colonnes dans une table peut prendre deux mois pour trois développeurs ! Véridique ! A cause de code SQL incompréhensible dans tous les coins ! Utiliser une couche objet (entity beans) permet d'abstraire SQL et donc de faciliter la maintenance Pas facile à faire avec des sessions beans Choix entre BMP et CMP Facilité de programmation : CMP Réduction du code à écrire. Énormes descripteurs.

Choix entre BMP et CMP Gestion des relations : CMP Depuis EJB 2.Choix entre BMP et CMP Debugging : CMP Parfois. l'argent rentre moins vite !!! Courbe d'apprentissage : BMP mais le plus souvent par simple peur de ne pas se lancer dans CMP . Gestion automatique de l'intégrité. etc… Containers très performants aujourd'hui. Avec BMP : beaucoup de code à écrire. projet plus long à développer. langage EJB-QL. les bugs dans les CMPs sont durs à trouver car tout se passe en coulisse… Un descripteur mal spécifié… Avec CMP on contrôle tout… Contrôle : BMP Avec BMP on contrôle tout.0. nombreuses améliorations. Mais les meilleurs containers ont des moteurs CMP très puissants et paramétrables… Portabilité : CMP Indépendant de la base de données.

là encore. il n'est plus nécessaires de concentrer les traitements pour minimiser les échanges entre beans.Choix de la granularité Doit-on faire de gros ou de petits composants? Depuis EJB 2. On peut faire de "petits" beans ! Exemple : commande contient des lignes de commandes.0 et les interfaces locales. il est préférable d'utiliser des procédures stockées. Sinon. on pouvait utiliser des classes normales sérialisables… Mais on perd tout l'avantage des relations en EJB 2. On n'hésite plus. chaque ligne est un entity bean ! Auparavant.0 ! Trucs et astuces sur la persistance Parfois. les procédures stockées peuvent centraliser une partie de la logique… . pour des traitements nécessitant l'examen d'un grand nombre de données. Exemple : trouver les comptes bancaires débiteurs… Éviter de partager une source de données entre une application à base d'EJB et une application externe.

migration difficile. il y a aussi de nombreuses raisons pour NE PAS utiliser des procédures stockées Tout repose sur le SGBD. Évident si la source de données n'existe pas au début du projet. adapter le modèle de données au modèle EJB. Mauvaise flexibilité. Maintenance ? Trucs et astuces sur la persistance Si on peut. N'oubliez pas que les données sont les données.Trucs et astuces sur la persistance Attention. les objets sont les données + le comportement ! . goulot d'étranglement Peu portable.

Sign up to vote on this title
UsefulNot useful