Vous êtes sur la page 1sur 252

Enterprise JavaBeans

Introduction gnrale
Michel Buffa (buffa@unice.fr), UNSA 2002

Les promesses des EJB


Enterprise JavaBeans
Standard industriel pour un modle de composant logiciel distribu, Permet d'implmenter des "objets mtier" d'une manire propre et rutilisable, Pour le dveloppement RAD d'applications ct serveur

Questions :
De quoi a-t-on besoin lorsqu'on dveloppe une application distribue oriente objet ? Qu'est-ce que les EJBs et qu'apportent-elles ? Quels sont les acteurs dans l'cosystme EJB ?

Motivation des EJBs


Considrons : un site de gestion de portefeuille boursier, une application bancaire, un centre d'appel, un systme d'analyse de risque Nous parlons ici d'applications distribues.

Choses considrer lorsqu'on construit une application distribue


Si on prend une application monolithique et qu'on la transforme en application distribue, o plusieurs clients se connectent sur plusieurs serveurs qui utilisent plusieurs SGBD, quels problmes se posent alors ?

Choses considrer lorsqu'on construit une application distribue


Protocoles d'accs distants (CORBA, RMI, IIOP) Gestion de la charge, Gestion des pannes, Persistence, intgration au back-end, Gestion des transactions, Clustering, Redploiement chaud, Arrt de serveurs sans interrompre l'application, Gestion des traces, rglages (tuning and auditing), Programmation multithread Problmes de nommage Securit, performances, Gestion des tats Cycle de vie des objets Gestion des ressources (Resource pooling) Requte 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 problmes, Gros risque : a revient cher (maintenance, dveloppement) Orthogonal au secteur d'activit de l'entreprise (banque, commerce)

Pourquoi ne pas acheter un produit ?


Oracle, IBM, BEA proposent depuis plusieurs annes des middleware Aussi appels serveurs d'application.

Serveur d'application : diviser pour rgner !


Un serveur d'application fournit les services middleware les plus courants, Permettent de se focaliser sur l'application que l'on dveloppe, sans s'occuper du reste. Le code est dploy sur le serveur d'application. Sparation des mtiers et des spcificits : d'un ct la logique mtier, 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 rutiliser une partie de la logique mtier ! Vous dveloppez votre application l'aide de composants.
Code qui implmente des interfaces prdfinies. Sorte de bote noire. Un bout de logique facilement rutilisable. Un composant n'est pas une application complte. Juste un bout. On assemble les composants comme un puzzle, afin de rsoudre des problmes importants.

Composant logiciel rutilisable


Une entreprise peut acheter un composant et l'intgrer avec des composants qu'elle a dvelopp.
Par exemple, un composant qui sait grer 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 trs complexe : remises, promotions, lots, clients privilgis, rgles complexes en fonction du pays, des taxes, etc

Composant logiciel rutilisable


Ce composant rpond un besoin rcurrent
Vente en ligne de matriel informatique, Gestion des cots sur une chane de production automobile, Calcul des prix des expditions par la poste, Etc

Composant logiciel rutilisable

Composant logiciel rutilisable

Composant logiciel rutilisable

Quel intrt ?
Moins d'expertise requise pour rpondre certains points du cahier des charges, Dveloppement plus rapide. Normalement, les vendeurs de composants assurent un service de qualit (BEA, IBM) Rduction des frais de maintenance. Naissance d'un march des composants.
Pas encore l'explosion attendue mais

Architectures de composants
Plus de 50 serveurs d'applications ont vu le jour depuis une dizaine d'annes, Au dbut, composants propritaires uniquement.
Pas de cohabitation entre composants dvelopps pour diffrents serveurs d'application Dpendant d'un fabriquant une fois le choix effectu.

Dur avaler pour les dveloppeurs java qui prnent la portabilit et l'ouverture !

Architectures de composants
Ncessit de standardiser la notion de composants
Ensemble de dfinitions 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 tl, au VHS, etc

Architectures de composants

Enterprise JavaBeans (EJB)


Le standard EJB est une architecture de composants pour des composants serveur crits en java.
1. 2. 3.

Adopt par l'industrie. "Train once, code anywhere" Portable facilement Rapid Application Development (RAD)

EJB signifie deux choses :


1. 2.

Une spcification Un ensemble d'interfaces

Pourquoi java ?
EJB = uniquement en java
Sparation entre l'implmentation et l'interface Robuste et sr : mcanismes + riche API + spcificit du langage (reflexivit, introspection, chargement dynamique) Portable

Autre possibilits
Composants Microsoft .NET CORBA : mais nombreux serveurs EJB bass sur CORBA)

EJB pour dvelopper des composants business


Implmenter de la logique mtier : calcul des taxes sur un ensemble d'achats, envoyer un mail de confirmation aprs une commande, etc Accder un SGBD Accder un autre systme d'information (CICS, COBOL, SAP R/3, etc) Applications web : intgration avec JSP/Servlets Web services bass sur XML (SOAP, UDDI, etc)
Exemple : DELL attaque le serveur d'INTEL directement travers un protocole XML pour rserver des pices.

EJB ne fournit pas de GUI

GUI = ct client
Applications classiques Servlets/JSP

L'cosystme EJB
Pour dployer et excuter un projet base d'EJBs, six mtiers sont impliqus 1 - Le fournisseur d'EJBs
Peut-tre un membre de votre quipe, ou bien une entreprise qui vend des EJBs (www.componentsource.com ou www.flashline.com pour voir une liste)

L'cosystme EJB
2 - L'assembleur d'application
Il s'agit de l'architecte de l'application Il est client des EJBs achetes ou dveloppes Il dcide de la combinaison de composants dont il a besoin Fournit un GUI l'application Conoit et dveloppe de nouveau composants Conoit et dveloppe les programmes clients Dfinit le mapping avec les donnes manipules par les diffrents composants En gnral, c'est un expert en Gnie Logiciel, en UML et en dveloppement Java. Il peut s'agir d'un intgrateur de systmes, d'un consultant, d'une quipe de dveloppeurs/concepteurs maison

L'cosystme EJB
3 - Le dployeur d'EJBs
Aprs que l'application ait t assemble, elle doit tre dploye sur un ou plusieurs serveurs d'application Attention la scurit (firewall, etc) Branchement de services annexes (LDAP, Lotus Notes, Microsoft Active Directory, etc) sur le serveur d'applications. Choix du hardware, des SGBD, etc Paramtrage du serveur d'application, optimisation des performances Il adapte les composants et le serveur l'application Il peut tre une quipe ou une personne, un consultant ou un vendeur d'hbergement de serveurs d'applications. Exemples aux USA : www.hostJ2EE.com ou www.loudcloud.com

L'cosystme EJB
4 - L'administrateur systme
Vrifie le bon fonctionnement de l'application en exploitation. Il utilise les outils de monitoring des serveurs d'application. Il effectue la maintenance hardware et software (lancement, arrt) du systme. Certains serveurs d'application savent tlphoner et appeler l'administrateur systme en cas de problme. Ponts avec les outils de Tivoli, Computer Associates, via JMX.

L'cosystme EJB
5 - Le fournisseur du serveur d'application et des containers
EJB container = environnement au sein du serveur dans lequel les EJB vivent. Le container EJB fournit les services middleware et manage les EJBs. Exemples : Weblogic, Websphere, BES, Oracle Orion Server, JRun, JBoss Il existe d'autre containers spcialiss (container Web comme Tomcat, Resin) Le fournisseur du serveur d'application est le mme que le fournisseur de containers EJB. On confond en gnral container et serveur d'application.

L'cosystme EJB
6 - Les vendeurs d'outils
Dvelopper une application base d'EJB est assez lourd. Pourtant la manire de dvelopper, construire, maintenir, dployer les EJBs est standard. Il est trs pratique d'utiliser un IDE pour simplifier les tches rptitives comme le dploiement, etc Principaux IDEs : JBuilder, Visual Age, Visual Cafe. Autres outils : les outils UML comme Together/J, Rational Rose Outil de test (JUnit), de stress (LodeRunner), etc

Les diffrents mtiers

Les diffrents mtiers


Bientt un nouveau mtier : le "persistence manager"
Dveloppe des outils qui se "branchent" sur le serveur d'application et implmentent les mcanismes de persistance. Mapping BD relationnelles/Objets Mapping BD objet/Objets Etc

Pas encore standardis dans la spcification EJB 2.0

La plate-forme Java J2EE


EJB = la cl de vote d'une architecture distribue java appele J2EE
Pour le dveloppement d'application serveur Ensemble de spcifications et d'APIs Contient deux autres architectures 1. J2ME (Java 2 Micro Edition) : pour les mobiles 2. J2SE : pour applications et applets standards Non attach un vendeur particulier. Quiconque respecte les spcification est "J2EE compliant" Applications dveloppes indpendantes des vendeurs d'outils.

La plate-forme Java J2EE


Chaque API dans J2EE sa propre spcification (PDF) Batterie de logiciel pour valider les implmentations (test suites) Implmentation de rfrence
J2EE est livre avec un serveur d'application par exemple

Ensemble de "blueprints" : dfinit prcisment le rle de chaque API (PDF)

J2EE : les APIs


J2EE comprend en plus de J2ME et J2SE
EJB : standard de dfinition de composants Java 2 RMI et RMI-IIOP : objets distribus 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

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.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, 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

EJB : les fondamentaux


Michel Buffa (buffa@unice.fr), UNSA 2002

Enterprise Bean
Composant serveur qui peut tre dploy Compos de un ou plusieurs objets Les clients d'un Bean lui parlent au travers d'une interface Cette interface, de mme que le Bean, suivent la spcification EJB Cette spcification requiert que le Bean expose certaines mthodes

Enterprise Bean
Le client d'un Bean peut tre
Une servlet Une applet Une application classique Un autre Bean

On peut dcomposer une application en un graphe de tches/sous-tches Exemple : achat d'un CD partir du code-barre
Scanner (qui a une JVM embarque) client d'un Bean sur le Serveur Ce Bean client d'autres Beans : gestion de catalogue, de commandes, de gestion de transaction VISA, etc

Modle flexible, extensible

3 types de Beans : Session Bean


Session Beans
Modlisent un traitement (business process) Correspondent des verbes, des actions Ex : gestion de compte bancaire, affichage de catalogue de produit, vrifieur de donnes bancaires, gestionnaire de prix Les actions impliquent des calculs, des accs une base de donnes, consulter un service externe (appel tlphonique, etc.)

Souvent clients d'autres Beans

3 types de Beans : Entity Bean


Entity beans
Modlisent des donnes Correspondent des noms Ce sont des objets java qui cachent des donnes d'une base de donnes Ce sont des objets persistants Ex : un Bean Personne, un Bean compte bancaire, un Bean produit, un Bean commande. Serveurs pour des Beans Session le plus souvent Servent de proxy entre la logique mtier et les base de donnes Mapping base de donne relationnelle/Objet facilit par EJB 2.0

Exemple de Session/Entity bean

Session Bean
Gestion de compte Vrificateur de CB

Entity Bean
Compte bancaire Carte de crdit

Systme d'entre gestion Commande, ligne de de commandes commande Gestion de catalogue Gestionnaire d'enchres Gestion d'achats Produits Enchre, Produit Commande, Produit, ligne de commande

3 types de Beans : Message-Driven Bean


Message-Driven Beans
Nouveau dans EJB 2.0, Similaire aux Session bean : reprsentent des verbes ou des actions, On les invoque en leur envoyant des messages, Ex : message pour dclencher des transactions boursires, des autorisations d'achat par CB, Souvent clients d'autres beans

3 types de Beans : pourquoi ?


Pas d'Entity Beans dans les solutions Microsoft par exemple Nombreuses compagnies impliques dans les standards EJB/J2EE
Leurs clients ont des besoins varis, Solution propose flexible mais plus complexe, Standard EJB plus difficile apprendre, Risque de mauvaise utilisation mais On est gagnant sur le long terme.

Clients interagissant avec un serveur base d'EJBs

Les objets distribus au cur des EJBs

Les objets distribus et le middleware


Lorsqu'une application devient importante, des besoins rcurrents apparaissent : scurit, transactions,etc C'est l qu'intervient le middleware! Deux approches
1. 2.

Middleware explicite, Middleware implicite

Middleware explicite

Middleware explicite
Exemple : transfert d'un compte bancaire vers un autre : transfert(Compte c1, Compte c2, long montant)
1. 2. 3. 4. 5. 6.

Appel vers l'API middleware qui fait une vrification de scurit, Appel vers l'API de transaction pour dmarrer une transaction, Appel vers l'API pour lire des lignes dans des tables d'une BD, 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, Appeler l'API de transaction pour terminer la transaction.

Middleware explicite
Difficile crire, Difficile maintenir, Votre code est dpendant des API du vendeur de middleware que vous utilisez.

Middleware implicite

Constitution d'un EJB : Enterprise Bean class


La classe du Bean (Enterprise Bean class)
Une classe qui implmente une interface prcise et qui respecte certaines rgles, Il s'agit de l'implmentation du bean lui-mme, Session Bean : logique mtier, calculs, transfert de compte bancaire, saisie de commandes, etc Entity Bean : logique oriente donne, par exemple comment changer le nom d'un client, diminuer un compte bancaire Message-Driven Bean : logique oriente message, traitement aprs rception d'un ordre d'achat d'actions boursires

Constitution d'un EJB : Enterprise Bean class


Interfaces implmentes par la classe du Bean
Tous les beans implmentent javax.ejb.EnterpriseBean : juste un marqueur, Important : cette interface drive de Serializable Chaque type de bean implmente des interfaces plus spcifiques : Javax.ejb.SessionBean Javax.ejb.EntityBean Javax.ejb.MessageDrivenBean

Constitution d'un EJB : EJB Object


Les clients n'invoquent jamais directement les mthodes de la classe du Bean Les appels de mthodes (requests) sont intercepts par le Container, afin d'assurer le traitement middleware implicite, Une fois ce traitement effectu, le container appelle les mthodes de la classe du Bean Le dveloppeur de composant se concentre sur la logique, ignore la partie middleware.

Constitution d'un EJB : EJB Object


Que se passe-t-il lors de l'interception ?
Prise en compte des transactions, Scurit : le client est-il autoris ? Gestion des ressources + cycle de vie des composants : threads, sockets, connexions DB, pooling des instances (mmoire), Persistance, Accs distant aux objets, Threading des clients en attente, Clustering, Monitoring : statistiques, graphiques temps rel du comportement du systme

Constitution d'un EJB : EJB Object


Container = couche d'indirection entre le client et le bean Cette couche est matrialise par un objet unique : l'EJB Object

Constitution d'un EJB : EJB Object


L'EJB Object contient du code spcifique au container (vendeur-dpendant) Il appelle les mthode de la classe du Bean, Il est gnr par le container ! Chaque container est livr avec des outils pour gnrer les EJB Object pour chaque Bean.

EJB : classe du Bean et EJB Object


EJ Bean EJ Bean Code simple
EJB Server

Gnration du code partir du Bean


Container EJB

Le code gnr fournit Transactions, Securit, Persistance, Accs Distant, gestion des ressources, etc. Fournit les services au container

EJB Container

EJ Bean EJ Bean

Serveur EJB

EJB Object : gnration du code


Utilisation du descripteur de dploiement (fourni par l'auteur du Bean)
Container EJB

EJ Bean EJ Bean

Paramtres de dploiement = securit, mappings objets/BD relationelle, etc.) Gnration du code pour intgrer le bean dans le container, ajout du plumbing (persistance, securit, etc)

Serveur EJB Container EJB

EJ Bean EJ Bean
Code gnr

Constitution d'un EJB : l'interface distante


Les clients invoquent les mthodes des EJB Objects, Ces EJB Objects doivent cloner toutes les mthodes que le bean expose, Comment l'outil qui gnre l'EJB Object peut-il connatre la liste des mthodes cloner ? Rponse : il utilise une interface fournie par le programmeur du bean, l'interface distante

Constitution d'un EJB : l'interface distante


public interface javax.ejb.EJBObject extends java.rmi.Remote { public abstract javax.ejb.EJBHome getEJBHome() throws java.rmi.RemoteException; public abstract java.lang.Object getPrimaryKey() throws java.rmi.RemoteException; public abstract void remove() throws java.rmi.RemoteException, javax.ejb.RemoveException; public abstract javax.ejb.Handle getHandle() throws java.rmi.RemoteException; public abstract boolean isIdentical(javax.ejb.EJBObject) throws java.rmi.RemoteException; }

Constitution d'un EJB : l'interface distante


Le programmeur du Bean drivera son interface distante de javax.ejb.EJBObject, Rajoutera les signatures des mthodes qu'il souhaite exposer, Qui implmentera cette interface ? L'EJB Object gnr par le container ! Presque rien faire pour le dveloppeur de bean !

Java RMI-IIOP et EJB Objects


Javax.ejb.EJBObject drive de java.rmi.Remote, Quiconque implmente Remote est appelable distance depuis une autre JVM, EJB Objects = RMI-IIOP + EJB compatibles RMI-IIOP = convention de passage de paramtres + valeurs de retour lors d'appels de mthode distante, entre autres

Constitution d'un EJB : Home Object


Nous avons vu comment les clients appelaient les mthodes d'un Bean : via l'EJB Object. Mais comment obtiennent-ils une rfrence sur l'EJB Object ? En effet : pas d'instanciations lorsque on travaille avec des objets distants ! Solution : le client demande la rfrence une fabrique d'EJB Objects (EJB Object Factory)
Design pattern!

Constitution d'un EJB : Home Object


L'EJB factory est responsable de l'instanciation et de la destruction des EJB Objects. La spcification EJB appelle cette factory un Home Object. Responsabilits du Home Object
Crer les EJB Objects, Trouver les EJB Objects existants (Entity beans seulement) Supprimer les EJB Objects.

Constitution d'un EJB : Home Object


Comme les EJB Objects, les Home Objects sont gnrs par le container
Contiennent du code spcifique, Assurent le load-balancing, etc

Constitution d'un EJB : l'interface Home


Comment un Home object sait de quelle manire le client veut initialiser l'EJB Object ?
Rappel : au lieu d'appeler un constructeur, on demande au Home object de retourner une rfrence. Comme pour les constructeurs, il est possible de passer des paramtres d'initialisation.

Comme pour les EJB Objects, le dveloppeur du bean doit spcifier une interface Home

Constitution d'un EJB : l'interface Home


L'interface Home dfinit
Les mthodes pour crer, dtruire et localiser les EJB Objects Le Home Object (gnr par le container) implmente cette interface. L'interface fournie par le dveloppeur drive de javax.ejb.EJBHome Javax.ejb.EJBHome drive de java.rmi.Remote Les Home objects sont aussi des objets distants, compatibles RMI-IIOP

Constitution d'un EJB : l'interface Home


public interface javax.ejb.EJBHome extends java.rmi.Remote { public EJBMetaData getEJBMetaData() throws java.rmi.RemoteException;

public javax.ejb.HomeHandle getHomeHandle() throws java.rmi.RemoteException;

public void remove(Handle handle) throws java.rmi.RemoteException javax.ejb.RemoveException;

public void remove(Object primaryKey) throws java.rmi.RemoteException, javax.ejb.RemoveException; }

Constitution d'un EJB : les interfaces locales


Problme : la cration de bean et l'appel de mthode distante cotent cher !

Constitution d'un EJB : les interfaces locales


Commentaires sur la figure prcdente
1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

Le client appelle un stub (souche), Le stub encode les paramtres dans un format capable de voyager sur le rseau, Le stub ouvre une connexion sur le skeleton (squelette), Le skeleton dcode les paramtres, Le skeleton appelle l'EJB Object, L'EJB Object effectue les appels middleware, L'EJB Object appelle la mthode du bean, Le Bean fait son travail, On fait le chemin inverse pour retourner la valeur de retour vers le client ! Sans compter le chargement dynamique des classes ncessaires !

Constitution d'un EJB : les interfaces locales


Nouveau dans EJB 2.0 : les interfaces locales. Introduit la notion de Local Object, en remplacement de EJB Object Les Local Objects implmentent une interface locale au lieu d'une interface distante Exemple d'appel de mthode distante
1. 2. 3.

Le client appelle le Local Object, Le Local Object appelle le middleware puis la mthode du bean La valeur de retour est renvoye au Local Object, puis au client

Constitution d'un EJB : les interfaces locales


Pour l'appel distant de mthodes, le dveloppeur peut fournir une interface locale, qui sera implmente par le container en tant que Local Object
A distinguer du cas "normal" (EJB 1.1) ou on a interface distante implmente par EJB Object

Pour la cration/localisation de beans, le dveloppeur peut fournir une interface home interface locale, qui sera implmente par le container en tant que Home Object local
A comparer avec Home Interface implmente 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 mme processus (mme container), Attention, paramtres et valeurs de retour (lors des appels de mthodes) se passent maintenant par rfrence
Toujours par valeur dans le cas d'appels distants! Plus performant mais smantique diffrente.

Difficile de passer d'une implmentation locale une implmentation classique


Aurait pu tre fait dans les descripteurs (weblogic)

Constitution d'un EJB : les descripteurs de dploiement


Pour informer le container des besoins middleware, on utilise un descripteur de dploiement (XML)
Standardis, A l'extrieur de l'implmentation du bean. Attention si on les crit la main! Outils d'aide au dploiement : IDEs (Jbuilder, Visual Cafe), outils spcifiques (Borland Application Server, Weblogic 6.1) Descripteurs peuvent tre modifis aprs le dploiement.

Constitution d'un EJB : les descripteurs de dploiement


Descripteurs spcifiques au serveur d'application
Chaque vendeur ajoute des trucs en plus : loadbalancing, persistance complexe, clustering, monitoring Dans des fichiers spcifiques (inprise-ejb.xml avec Borland)

Dploiement : un fichier .jar

Rsum
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 dploiement standard Descripteurs spcifiques au vendeur Fichier .jar de l'EJB

Ecriture d'un premier Bean


Hello World ! Comme c'est original !
Michel Buffa (buffa@unice.fr), UNSA 2002

Comment s'y prendre ?


Ordre typique des oprations
1. 2. 3. 4. 5. 6. 7.

Ecrire les fichiers .java qui composent le bean, Ecrire le descripteur du bean, Compiler les .java de l'tape 1, Crer un .jar contenant les .class et le descripteur, Deployer le .jar (via outil ou simple copie), Vrifier que le serveur fonctionne et a bien dploy le bean, sinon, vrifier la config, Ecrire, compiler, excuter un client de test du bean.

Modle objet du bean HelloWorld

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

L'interface locale
package examples; /** * This is the HelloBean local interface. * * This interface is what local clients operate * on when they interact with EJB local objects. * The container vendor will implement this * interface; the implemented object is the * EJB local object, which delegates invocations * to the actual bean. */ public interface HelloLocal extends javax.ejb.EJBLocalObject { /** * The one method - hello - returns a greeting to the client. */ public String hello(); }

L'interface Home
package examples; /** * This is the home interface for HelloBean. This interface * is implemented by the EJB Server's tools - the * implemented object is called the Home Object, and serves * as a factory for EJB Objects. * * One create() method is in this Home Interface, which * corresponds to the ejbCreate() method in HelloBean. */ public interface HelloHome extends javax.ejb.EJBHome { /* * This method creates the EJB Object. * * @return The newly created EJB Object. */ Hello create() throws java.rmi.RemoteException, javax.ejb.CreateException; }

L'interface Home locale


package examples; /** * This is the local home interface for HelloBean. * This interface is implemented by the EJB Server's * tools - the implemented object is called the * local home object, and serves as a factory for * EJB local objects. */ public interface HelloLocalHome extends javax.ejb.EJBLocalHome { /* * This method creates the EJB Object. * * @return The newly created EJB Object. */ HelloLocal create() throws javax.ejb.CreateException; }

La classe du bean
package examples; /** * Demonstration stateless session bean. */ public class HelloBean implements javax.ejb.SessionBean { private SessionContext ctx; // // EJB-required methods // public void ejbCreate() { System.out.println("ejbCreate()"); } public void ejbRemove() { System.out.println("ejbRemove()"); } public void ejbActivate() { System.out.println("ejbActivate()"); } public void ejbPassivate() { System.out.println("ejbPassivate()"); } } } public void setSessionContext(javax.ejb.SessionContext ctx) { this.ctx = ctx; }

// // Business methods // public String hello() { System.out.println("hello()"); return "Hello, World!";

La classe du bean
ejbCreate() correspond au create() de l'interface Home Une seule mthode mtier : hello()
On la retrouve dans les interfaces distante et locales.

ejbActivate() et ejbPassivate() n'ont pas d'utilit dans le cas de session bean stateless
Elles sont vides. Etudies plus tard.

Les EJBContexts : le lien avec le container


Sert encapsuler le domaine dans lequel volue le bean dans un objet. setSessionContext() appel par le container. Un contexte par type de Bean
SessionContext, EntityContext, MesageDrivenContext Mthodes correspondantes setSessionContext(), setEntityContext(), setMessageDrivenBeanContext()

Les EJBContexts : le lien avec le container


Tous les contextes implmentent
public interface javax.ejb.EJBContext { /* * Call these from within your bean to access * your own home object or local home object. * * You can use them to create, destroy, or * find EJB objects and EJB local objects * of your own bean class type. */ public javax.ejb.EJBHome getEJBHome(); public javax.ejb.EJBLocalHome getEJBLocalHome(); ..

Les EJBContexts : le lien avec le container


.. /* * These are transaction methods - see Chapter X */ public boolean getRollbackOnly(); public void setRollbackOnly(); public javax.transaction.UserTransaction getUserTransaction();

/* * These are security methods - see Chapter X */ public boolean isCallerInRole(java.lang.String); public java.security.Principal getCallerPrincipal(); }

Les EJBContexts : le lien avec le container

Le descripteur de dploiement
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_2_0.dtd"> <ejb-jar> <enterprise-beans> <session> <ejb-name>Hello</ejb-name> <home>examples.HelloHome</home> <remote>examples.Hello</remote> <local-home>examples.HelloLocalHome</local-home> <local>examples.HelloLocal</local> <ejb-class>examples.HelloBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> </ejb-jar>

Le descripteur de dploiement spcifique


Selon les serveurs d'application, il peut y avoir un descripteur en plus, spcifique. Voir pendant les exercices

Le fichier .jar de l'EJB


Il faut mettre tous les fichiers compils + descripteurs dans un .jar Depuis un IDE ou la main
jar cf HelloWorld.jar *

Contenu de HelloWorld.jar
META-INF/MANIFEST.MF META-INF/ejb-jar.xml examples/HelloBean.class examples/HelloLocalHome.class examples/HelloHome.class examples/HelloLocal.class examples/Hello.class

Dployer le bean
Cette tape varie selon le container
Simple copie avec JBoss, A l'aide d'un outil de dploiement spcifique (BAS)

Lors du dploiement
Vrification du fichier.jar, Le container gnre les EJBObjects et EJBHome, Le container gnre les stubs et skeletons pour les appels RMI-IIOP.

Vrifier le dploiement
Le serveur doit vous avertir qu'il a bien charg le bean.

criture d'un client


Deux types de clients
1.

2.

Clients JAVA RMI-IIOP : ils utilisent JNDI pour localiser les objets et Java Transaction API pour contrler les transactions. 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. 3. 4.

Localiser (lookup) un objet Home, Utiliser cet objet Home pour crer (create) un EJBObject, Appeler les mthodes de l'EJBObject, Supprimer (remove) l'EJBObject.

Client : localiser (lookup) un objet Home,


On ne sait pas o se trouve l'objet Utilisation de JNDI
JNDI sert mapper des ressources sur des noms logiques : utilisateurs, services, imprimantes, EJB, Datasource (base de donnes) JNDI est un pont vers des services tels que LDAP, Microsoft Active Directory, Lotus Notes Domino Server, iPlanet Directory Server

JNDI permet de rendre transparente la localisation des objets

Client : les tapes en images

Client : le code
package examples; import javax.naming.Context; import javax.naming.InitialContext; import java.util.Properties; /** * This class is an example of client code which invokes * methods on a simple stateless session bean. */ public class HelloClient { public static void main(String[] args) throws Exception { /* Setup properties for JNDI initialization. * These properties will be read-in from * the command-line. */ Properties props = System.getProperties(); /* Obtain the JNDI initial context. * The initial context is a starting point for * connecting to a JNDI tree. We choose our JNDI * driver, the network location of the server, etc * by passing in the environment properties. */ Context ctx = new InitialContext(props); ..

Client : le code
... /* Get a reference to the home object - the * factory for Hello EJB Objects */ Object obj = ctx.lookup("HelloHome"); /* Home objects are RMI-IIOP objects, and so * they must be cast into RMI-IIOP objects * using a special RMI-IIOP cast. * See Appendix X for more details on this. */ HelloHome home = (HelloHome) javax.rmi.PortableRemoteObject.narrow(obj, HelloHome.class); /* Use the factory to create the Hello EJB Object */ Hello hello = home.create(); /* Call the hello() method on the EJB object. * receive the result, and return it to us. * We then print the result to the screen. */ System.out.println(hello.hello()); /* Done with EJB Object, so remove it. * The container will destroy the EJB object. */ hello.remove(); } } The * EJB object will delegate the call to the bean,

Excution du client de test


Place aux exercices !!!! Tiens, une question : que reprsente le mot-cl this pour un EJB ?

Introduction aux Session Beans


Michel Buffa (buffa@unice.fr), UNSA 2002

Session Bean : rappel


Un Session Bean reprsente
une action, un verbe, une logique mtier, un algorithme, Un enchanement de tches

Exemples
Saisie d'une commande, Compression vido, Gestion d'un caddy, d'un catalogue de produits, Transactions bancaires

Dure de vie d'un Session Bean


Dure de vie = la session
En gros, le temps qu'un client reste connect sur le bean. Dans une logique e-commerce, le temps qu'un utilisateur est connect sur le site.

Le container cre une instance lorsqu'un client se connecte sur le Session Bean. Il peut le dtruire lorsque le client se dconnecte. Les Session Beans ne rsistent pas des crashes du serveur.
Ce sont des objets en mmoire, non persistants. Le contraire des Entity Beans que nous verrons plus tard.

Types de Session Beans


Chaque EJB a un moment donn entretient une conversation avec un client.
Conversation = suites d'appels de mthodes.

Il existe deux types de Session Beans


1. 2.

Stateful Session Beans, Stateless Session Beans.

Chacun modlisant un type particulier de conversation.

Stateful Session Beans


Certaines conversations se droulent sous forment de requtes succesives.
Exemple : un client surfe sur un site de ecommerce, slectionne des produits, remplit son caddy

D'une requte HTTP l'autre, il faut un moyen de conserver un tat (le caddy par ex.)
Autre exemple : une application bancaire. Le client effectue plusieurs oprations. On en va pas chaque fois lui redemander son No de compte

Stateful Session Beans


En rsum, un Stateful Session Bean est utile pour maintenir un tat pendant la dure de vie du client
au cours d'appels de mthodes successifs. Au cours de transactions successives. Si un appel de mthode change l'tat du Bean, lors d'un autre appel de mthode l'tat sera disponible.

Consquence : une instance de Stateful Session Bean par client. Avec certains containers, les Stateful Session Beans peuvent tre persistants (BAS/BES) par srialisation.

Stateless Session Beans


Certaines conversations peuvent se rsumer un appel de mthode, sans besoin de connatre l'tat courant du Bean
Ex : simple traitement, simple calcul (validation de No de CB), compression Le client passe toutes les donnes ncessaires au traitement lors de l'appel de mthode.

Le container est responsable de la cration et de la destruction du Bean


Il peut le dtruire juste aprs un appel de mthode, ou le garder en mmoire pendant un certain temps pour rutilisation.

Une instance de Stateless Session Bean n'est pas propre un client donn, elle peut tre partage entre chaque appel de mthode.

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 mme client appelle une autre mthode. Problme si trop de clients utilisent ce type de Bean en mme temps.
Ressources limites (connexions, mmoire, sockets) Mauvaise scalabilit du systme, L'tat peut occuper pas mal de mmoire

Problme similaire la gestion des tches dans un OS

Pooling des Stateful Session Beans


Avec un OS : on utilise le concept de mmoire virtuelle Lorsqu'un processus ne fait plus rien (Idle), on swappe son tat mmoire sur disque dur, librant de la place. Lorsqu'on a de nouveau besoin de ce processus, on fait l'inverse. 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 mthode, un client ne fait rien (Idle), Un utilisateur d'un site de e-commerce lit les infos sur la page www, rflchit de temps en temps il clique sur un bouton Pendant qu'il ne fait rien, l'tat du bean est swapp mais les ressources telles que les connexions BD, sockets, la mmoire intrinsque qu'il occupe, peuvent tre utilises par un autre client. Etc

Pooling des Stateful Session Beans


Ceci a un cot : l'activation/passivation gnre 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 rgles de la srialisation d'objets en java.
En effet, la passivation (swap de la mmoire vers le HD) et l'activation (l'inverse) sont ralises par srialisation.

Rappelez-vous que javax.ejb.EnterpriseBean implmente java.io.Serializable Tous les attributs du Bean non transcients sont donc concerns.

En quoi consiste l'tat d'un Bean Stateful?


Sont concernes galement tous les attributs issus du container
Rfrences vers EJBObject, EJBHome, EJBContext, contextes JNDI

Passivation d'un Stateful Session Bean

Activation d'un Stateful Session Bean

Activation/Passivation callbacks
Lorsqu'un bean va tre mis en passivation, le container l'avertit en appelant sa mthode ejbPassivate()
Il peut librer des ressources (connexions)

Idem lorsque le bean vient d'tre activ, le container appelle ejbActivate()

Count : l'interface distante


package examples; import javax.ejb.*; import java.rmi.RemoteException; /** * These are CountBean s business logic methods. * * This interface is what clients operate on when they * interact with EJB objects.The container vendor will * implement this interface;the implemented object is * the EJB object,which delegates invocations to the * actual bean. */ public interface Count extends EJBObject { /** * Increments the int stored as conversational state */ public int count()throws RemoteException; }

CountBean : la classe du bean


package examples; import javax.ejb.*; /** * Demonstration Stateful Session Bean.This Bean is initialized * to some integer value,and has a business method which * increments the value. * * This example shows the basics of how to write a stateful * session bean,and how passivation/activation works. */ public class CountBean implements SessionBean { // The current counter is our conversational state. public int val; // //Business methods //

CountBean : la classe du bean


/** Counts up */ public int count(){ System.out.println("count()"); return ++val; } // // EJB-required methods // public void ejbCreate(int val)throws CreateException { this.val =val; System.out.println("ejbCreate()"); } public void ejbRemove(){ System.out.println("ejbRemove()"); } public void ejbActivate(){ System.out.println("ejbActivate()"); } public void ejbPassivate(){ System.out.println("ejbPassivate()"); } public void setSessionContext(SessionContext ctx){ } }

CountBean : la classe du bean


Val est serializable, reprsente l'tat du bean Le bean est stateful mais ce n'est prcis nulle part dans le code. setSessionContext(SessionContext)
Appel par le container, L'objet SessionContext implmente
public interface javax.ejb.SessionContext extends javax.ejb.EJBContext { public javax.ejb.EJBLocalObject getEJBLocalObject(); public javax.ejb.EJBObject getEJBObject(); }

Ces deux mthodes permettent de rcuprer une rfrence sur l'EJBObject associ au Bean, remplace le this pour les EJB !

CountHome : l'interface Home


package examples; import javax.ejb.*; import java.rmi.RemoteException; /** * This is the home interface for CountBean. This interface * is implemented by the EJB Servers glue-code tools - the * implemented object is called the Home Object, and serves * as a factory for EJB Objects. * * One create() method is in this Home Interface, which * corresponds to the ejbCreate() method in the CountBean file. */ public interface CountHome extends EJBHome { /* * This method creates the EJB Object. * @param val Value to initialize counter to * @return The newly created EJB Object. */ Count create(int val) throws RemoteException, CreateException; }

ejb-jar.xml : descripteur de dploiement


<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd"> <ejb-jar> <enterprise-beans> <session> <ejb-name>Count</ejb-name> <home>examples.CountHome</home> <remote>examples.Count</remote> <ejb-class>examples.CountBean</ejb-class> <session-type>Stateful</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> </ejb-jar>

Descripteur de dploiement propritaire


Rien de spcial signaler Truc intressant faire : indiquer au container que l'on ne dsire pas plus de deux instances de l'EJB dans le pool.
Si on cre trois Beans, a va obliger le container mettre en uvre le pooling, swapper l'tat d'une instance lors des requtes

Client de l'EJB
package examples; import javax.ejb.*; import javax.naming.*; import java.util.Properties; /** This class is a simple example of client code. * We create 3 EJB Objects in this example, but we only allow * the container to have 2 in memory. This illustrates how * beans are passivated to storage. */ public class CountClient { public static void main(String[] args) { try { /* Get System properties for JNDI initialization */ Properties props = System.getProperties(); /* Get a reference to the Home Object - the * factory for EJB Objects */ Context ctx = new InitialContext(props); CountHome home = (CountHome) javax.rmi.PortableRemoteObject.narrow( ctx.lookup("CountHome"), CountHome.class);

Client de l'EJB
/* An array to hold 3 Count EJB Objects */ Count count[] = new Count[3]; int countVal = 0; /* Create and count() on each member of array */ System.out.println("Instantiating beans . . . "); for (int i=0; i < 3; i++) { /* Create an EJB Object and initialize it * to the current count value */ count[i] = home.create(countVal); /* Add 1 and print */ countVal = count[i].count(); System.out.println(countVal); /* Sleep for 1/2 second */ Thread.sleep(500); } // try ...

Client de l'EJB
/* Lets call count() on each EJB Object to * make sure the beans were passivated and * activated properly. */ System.out.println("Calling count() on beans . . . "); for (int i=0; i < 3; i++) { /* Add 1 and print */ countVal = count[i].count(); System.out.println(countVal); /* Sleep for 1/2 second */ Thread.sleep(500); } // for /* Done with EJB Objects, so remove them */ for (int i=0; i < 3; i++) { count[i].remove(); } } catch (Exception e) { e.printStackTrace(); } // try } // main }

Excution du client, dploiement du Bea,n


Sortie client
Instantiating beans . . . 1 2 3 Calling count() on beans . . . 2 3 4

Sortie serveur
ejbCreate() count() ejbCreate() count() ejbCreate() ejbPassivate() count() ejbPassivate() ejbActivate() count() ejbPassivate() ejbActivate() count() ejbPassivate() ejbActivate() ... count() ejbPassivate() ejbActivate() count() ejbPassivate() ejbActivate() ejbRemove() ejbActivate() ejbRemove() ejbRemove()

Cycle de vie d'un Session Bean stateless

Cycle de vie d'un Session Bean stateful

Introduction aux Entity Beans


Michel Buffa (buffa@unice.fr), UNSA 2002

Entity Bean, introducton


Un Entity Bean reprsente
Des objets persistants stocks dans une base de donne, Des noms, des donnes

Dans ce chapitre on tudiera


Le concept de persistance, Ce qu'est un entity bean, du point de vue du programmeur, Les caractristiques des entity beans, Les concepts de programmation des entity beans.

La persistance par srialisation


Srialisation = sauvegarde de l'tat d'un objet sous forme d'octets.
Rappel : l'tat d'un objet peut tre quelque chose de trs compliqu. Etat d'un objet = ses attributs, y compris les atributs hrits. Si les attributs sont eux-mme des instances d'une classe, il faut sauvegarder aussi les attributs de ces instances, etc

A partir d'un tat srialis, on peut reconstruire l'objet En java, au travers de l'interface java.io.Serializable, des mthodes de java.io.ObjectInputStream et java.io.ObjectOutputStream

La persistance par srialisation


Dfauts nombreux Gestion des versions, maintenance Pas de requtes complexes
Ex : on srialize mille comptes bancaires. Comment retrouver ceux qui ont un solde ngatif ?

Solution : stocker les objets dans une base de donne!

La persistance par mapping objet/BD relationelle


On stocke l'tat d'un objet dans une base de donne. Ex : la classe Personne possde deux attributs nom et prenom, on associe cette classe une table qui possde deux colonnes : nom et prenom. On dcompose chaque objet en une suite de variables dont on stockera la valeur dans une ou plusieurs tables. Permet des requtes complexes.

La persistance par mapping objet/BD relationelle

La persistance par mapping objet/BD relationelle


Pas si simple
Dtermination de l'tat d'un objet parfois difficile, tout un art Il existe des produits pour nous y aider TopLink (WebGain), JavaBlend (Sun), Aujourd'hui la plupart des gens font a la main avec JDBC ou SQL/J. Mais SQL dur tester/debugger source de nombreuses erreurs

La persistance l'aide d'une BD Objet


Les Base de donnes objet stockent directement des objets. 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.

Qu'est-ce qu'un Entity Bean


Ce sont des objets qui savent se mapper dans une base de donne. Ils utilisent un mcanisme de persistance (parmi ceux prsents) Ils servent reprsenter sous forme d'objets des donnes situes dans une base de donne
Le plus souvent un objet = une ou plusieurs ligne(s) dans une ou plusieurs table(s)

Qu'est-ce qu'un Entity Bean


Exemples
Compte bancaire (No, solde), Employ, service, entreprises, livre, produit, Cours, lve, examen, note,

Mais au fait, pourquoi nous embter passer par des objets ?


Plus facile manipuler par programme, Vue plus compacte, on regroupe les donnes dans un objet. On peut associer des mthodes simples pour manipuler ces donnes On va gagner la couche middleware !

Exemple avec un compte bancaire

On lit les informations d'un compte bancaire en mmoire, dans une instance d'un entity bean, On manipule ces donnes, on les modifie en changeant les valeurs des attributs d'instance, Les donnes seront mises jour dans la base de donnes automatiquement ! Instance d'un entity bean = une vue en mmoire des donnes physiques

Fichiers composant un entity bean


Idem session beans : interface locale, remote, home, local home, classe du bean, descripteur. Quelques particularits cependant
La classe du bean se mappe dans une base de donnes. Elle doit fournir certaines mthodes obligatoires, qui seront appeles par le container + des mthodes de manipulation simples des donnes. Il est ncessaire d'avoir une classe du type de la cl primaire du bean. Cl primaire = un objet srializable, unique pour chaque instance. C'est la cl primaire au sens SQL.

Caractristiques des entity beans


Survivent aux crashes du serveur, du SGBD Ce sont des vues sur des donnes dans un SGBD

Caractristiques des entity beans


Plusieurs instances d'entity beans peuvent reprsenter les mmes donnes
Plusieurs client peuvent accder aux mmes donnes (compte bancaire par exemple) Un seul thread par bean dans le modle EJB, code plus simple crire, Mais alors, il faut synchroniser les beans en mmoire pour qu'ils se rafrachissent lorsque les donnes changent. Mais oui ! On peut mme modifier les donnes dans le SGBD depuis un mcanisme extrieur ! Dpend de la politique de transaction du bean.

Caractristiques des entity beans


Pool d'instances d'un entity bean
Partage d'instances par plusieurs clients. Recyclage des instances Processus similaire aux session beans stateful

Caractristiques des entity beans


Pas si simple que pour les Session Beans
Comment librer les ressources (connexions, sockets)

Deux mthodes de callback


ejbActivate() : appele par le container lorsque le bean va recevoir un nouvel EJBObject et de nouvelles donnes dont une cl primaire. Dans ce callback on doit acqurir des ressources (socket) ejbPassivate() : appele lorsque le bean va tre swapp sur disque. Il faut librer les ressources.

Caractristiques des entity beans


Juste avant la passivation, la mthode ejbStore() est appele. Elle s'occupe de sauvegarder l'tat du bean dans une BD. Idem, au moment de l'activation, le bean doit lire son tat depuis la BD. Ceci est ralis en appelant ejbLoad().

Caractristiques des entity beans

Deux manires d'assurer la persistance


Bean Managed Entity Bean (BMP)
Persistance effectue la main, le plus souvent avec JDBC/SQL, si la BD est relationnelle. Sauvegarde, relecture, recherche, tout est faire par le programmeur + dterminer l'tat d'un objet (peut devenir trs 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. Peut se faire au moment du dploiement. Rduit la taille du code, Dveloppement plus rapide Grosse plus-value du modle EJB.

Cration d'entity beans

Suppression d'entity beans

Recherche d'entity beans


Les entity beans correspondant des lignes dans une BD, on peut avoir besoin de faire des recherches. Similaire un SELECT Se traduit par la prsence de mthodes "finders" dans l'interface HOME
findByPrimaryKey(), findAll() findCheapProducts()

Plus d'informations dans les prochains chapitres

Modifier les donnes sans passer par le bean

Contexte d'un entity bean


public interface javax.ejb.EJBContext { public javax.ejb.EJBHome getEJBHome(); public javax.ejb.EJBLocalHome getEJBLocalHome(); public java.security.Principal getCallerPrincipal(); public boolean isCallerInRole(java.lang.String); public void setRollbackOnly(); public boolean getRollbackOnly(); }

public interface javax.ejb.EntityContext extends javax.ejb.EJBContext { public javax.ejb.EJBLocalObject getEJBLocalObject(); public javax.ejb.EJBObject getEJBObject(); public java.lang.Object getPrimaryKey(); }

Contexte d'un entity bean


getEJBLocalObject() et getEJBObject() permettent d'obtenir une rfrence sur l'EJB Object associ au bean.
Le this pour les EJB !

getPrimaryKey() : utile lorsqu'on crit des entity en mode BMP


On l'utilise depuis ejbLoad() pour savoir quelle donne il faut lire. Depuis ejbRemove(), pour savoir quelle donne il faut supprimer.

Bean-Managed Persistent Entity Beans (BMP)


Michel Buffa (buffa@unice.fr), UNSA 2002

BMP entity beans


Le premier type d'entity bean, Le programmeur doit assurer l'implmentation de toute la logique d'accs aux donnes, Typiquement, l'aide de JDBC

Implmentation des BMP : les bases


La classe du Bean doit driver de javax.ejb.EntityBean
public interface javax.ejb.EnterpriseBean implements java.io.Serializable { }

public interface javax.ejb.EntityBean implements javax.ejb.EnterpriseBean { public void setEntityContext(javax.ejb.EntityContext); public void unsetEntityContext(); public void ejbRemove(); public void ejbActivate(); public void ejbPassivate(); public void ejbLoad(); public void ejbStore(); }

Recherche d'entity beans existants : ejbFind()


Par rapport l'interface javax.ejb.EntityBean, il est ncessaire d'implmenter des mthodes finders. Ces mthodes commencent toutes par ejbFind()
Ces mthodes sont utilises pour rechercher des donnes dans une BD, appartenant la mme classe d'objets. Par exemple, toutes les Personnes

Ces mthodes ne sont ncessaires avec les Entity Beans CMP (Container Managed Persistence)

Quelques exemples de mthodes finder


/** Finds the unique bank account indexed by primary key key */ public AccountPK ejbFindByPrimaryKey(AccountPK key) { ... }

/** Finds all the product entity beans. keys. */

Returns a Collection of primary

public Collection ejbFindAllProducts() { ... }

/** Finds all Bank Accounts that have at least a minimum balance. Returns a Collection of primary keys. */ public Collection ejbFindBigAccounts(int minimum) { ... }

/** Finds the most recently placed order */ public OrderPK ejbFindMostRecentOrder() { ... }

Quelques rgles propos des mthodes finder


Toutes les mthodes commencent par ejbFind Au moins une mthode finder : ejbFindByPrimaryKey On peut avoir plusieurs mthodes, avec des noms et des paramtres diffrents, Les finders renvoient soit la cl primaire soit une Collection de cls primaires,

Quelques rgles propos des mthodes finder


Comme avec ejbCreate(), les clients n'invoquent pas directement les mthodes finders du bean. Ils passent par les mthodes de l'objet Home. Pour chaque finder dans le bean, il faut une mthode correspondante dans l'objet Home
Dans le Home : public Account findBigAccounts(int minimum); Dans le Bean : public AccountPK ejbFindBigAccounts(int minimum) { ... }

Quelques rgles propos des mthodes finder


Comme pour ejbCreate(), il y a des diffrences entre la signature de la mthode dans le Home ou dans le Bean :
Dans le bean, la mthode renvoie la cl primaire au container, Dans le Home, c'est un EJB Object qui est renvoy.

Le nom change, on ajoute ejb comme prfixe dans la mthode du Bean


Comment la mthode du Bean est-elle appele ?

Quelques rgles propos des mthodes finder


Les finders peuvent renvoyer des Collections
public Collection findAllProducts(); public Collection ejbFindAllProducts() { ... }

findindAllProducts() renvoie une Collection de cls primaires au container, Le container la transforme en Collection d'EJB Objects

Exemple : un compte bancaire


Remarque : en production, pour un tel bean, on aura besoin surtout des interfaces locales, Mais pour nos essais, pour pouvoir tester le bean via un client de test, on va devoir l'invoquer distance.
On crira donc les interfaces Remote

Exemple : un compte bancaire

Account.java : l'interface Remote


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

Account.java : l'interface Local


package examples; import javax.ejb.*; /** This is the local interface for AccountBean. * This interface is what clients operate on when they interact with * beans. The container will implement this interface; the * implemented object is called the local object, which delegates * invocations to the actual bean.*/ public interface AccountLocal extends EJBLocalObject { /** Deposits amt into account.*/ public void deposit(double amt) throws AccountException; /** Withdraws amt from bank account. * @throw AccountException thrown in amt < available balance */ public void withdraw(double amt) throws AccountException; // Getter/setter methods on Entity Bean fields public double getBalance(); public String getOwnerName(); public void setOwnerName(String name); public String getAccountID(); public void setAccountID(String id); }

Account.java : l'interface Home


package examples; import javax.ejb.*; import java.util.Collection; import java.rmi.RemoteException; /** This is the home interface for Account. This * interface is implemented by the EJB container's tools - the * implemented object is called the home object, which * is a factory for EJB objects. */ public interface AccountHome extends EJBHome { /** We define a single create() method is in this home interface, * which corresponds to the ejbCreate() method in AccountBean. * This method creates the EJB object. * @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. */ Account create(String accountID, String ownerName) throws CreateException, RemoteException; ...

Account.java : l'interface Home (suite)


... /** Finds a Account by its primary Key (Account ID) */ public Account findByPrimaryKey(AccountPK key) throws FinderException, RemoteException;

/** Finds a Account by its owner name (assume there is only 1) */ public Collection findByOwnerName(String name) throws FinderException, RemoteException;

/** This home business method is independent of any particular * account. It returns the total of all accounts in the bank.*/

public double getTotalBankValue() throws AccountException, RemoteException; }

Account.java : l'interface Local Home


package examples; import javax.ejb.*; import java.util.Collection; /* This is the local home interface for Account. This * interface is implemented by the EJB container's tools - the * implemented object is called the local home object, which * is a factory for local EJB objects. */ public interface AccountLocalHome extends EJBLocalHome { /** We define a single create() method is in this home interface, * which corresponds to the ejbCreate() method in AccountBean. * This method creates the local EJB object. * Notice that the local home interface returns a * local interface, whereas the bean returns a PK. * Notice we don't throw RemoteExceptions because we are * local not remote. * @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. */ AccountLocal create(String accountID, String ownerName) throws CreateException; ...

Account.java : l'interface Local Home (suite)


... /** Finds a Account by its primary Key (Account ID) */ public AccountLocal findByPrimaryKey(AccountPK key) throws FinderException; /** Finds a Account by its owner's name (assume there is only 1 */ public Collection findByOwnerName(String name) throws FinderException; /** This home business method is independent of any particular * account instance. It returns the total of all the bank

* accounts in the bank. */ public double getTotalBankValue() throws AccountException; }

AccountPK.java : la classe de la cl primaire


package examples; import java.io.Serializable; /** Primary Key class for Account.*/ public class AccountPK implements java.io.Serializable { public String accountID; // example : "ABC-123-0000" public AccountPK(String id) { this.accountID = id; } public AccountPK() {} public String toString() { return accountID; } public int hashCode() { return accountID.hashCode(); } public boolean equals(Object account) { } } // Requiered ! // Requiered, for being able to be stored in hastables // Requiered !

return ((AccountPK)account).accountID.equals(accountID);

AccountBean.java
Comme le source est long, nous le dcomposons en 3 parties
1.

Les attributs qui font partie de l'tat persistant de l'objet, Les mthodes business (la logique mtier) Les mthodes requises par la specification EJB.

2. 3.

AccountBean.java : les attributs


package examples; import java.sql.*; import javax.naming.*; import javax.ejb.*; import java.util.*; import java.rmi.RemoteException; /** Demonstration Bean-Managed Persistent Entity Bean. * This Entity Bean represents a Bank Account.*/ public class AccountBean implements EntityBean { protected EntityContext ctx; // Bean-managed state fields private String accountID; // Primary Key private String ownerName; private double balance; public AccountBean() { System.out.println("New Bank Account Entity Bean Java Object created by EJB Container."); } ... methods continue ...

AccountBean.java : mthodes business (1)


... continued ... // Business Logic Method /** Deposits amt into account.*/ public void deposit(double amt) throws AccountException { System.out.println("deposit(" + amt + ") called."); balance += amt; } /** Withdraws amt from bank account. * @throw AccountException thrown in amt < available balance */ public void withdraw(double amt) throws AccountException { System.out.println("withdraw(" + amt + ") called."); if (amt > balance) { throw new AccountException("Your balance is " + balance + "! } balance -= amt; } ... You cannot withdraw " + amt + "!");

AccountBean.java : mthodes business (2)


// Getter/setter methods on Entity Bean fields public double getBalance() { System.out.println("getBalance() called."); return balance; } public void setOwnerName(String name) { System.out.println("setOwnerName() called."); ownerName = name; } public String getOwnerName() { System.out.println("getOwnerName() called."); return ownerName; } public String getAccountID() { System.out.println("getAccountID() called."); return accountID; }

AccountBean.java : mthodes business (3)


public void setAccountID(String id) { System.out.println("setAccountID() called."); this.accountID = id; } /** This home business method is independent of any * particular account instance. It returns the total * of all the bank accounts in the bank. */ public double ejbHomeGetTotalBankValue() throws AccountException { PreparedStatement pstmt = null; Connection conn = null; try { System.out.println("ejbHomeGetTotalBankValue()"); /* Acquire DB connection */ conn = getConnection(); /* Get the total of all accounts */ accounts"); pstmt = conn.prepareStatement("select sum(balance) as total from

AccountBean.java : mthodes business (4)


... ResultSet rs = pstmt.executeQuery(); /* Return the sum */ if (rs.next()) { return rs.getDouble("total"); } } catch (Exception e) { e.printStackTrace(); throw new AccountException(e); } finally { /* Release DB Connection for other beans */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) {} try { if (conn != null) conn.close(); } catch (Exception e) {} } throw new AccountException("Error!"); } ...

AccountBean.java : mthodes business (5)


... /** Gets JDBC connection from the connection pool. * @return The JDBC connection */ public Connection getConnection() throws Exception { try { Context ctx = new InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup("java:comp/env/jdbc/ejbPool"); return ds.getConnection(); } catch (Exception e) { System.err.println("Could not locate datasource! e.printStackTrace(); throw e; } } } // End of business methods ! Reason:");

AccountBean.java : mthodes business (6)


Remarques
Ouverture de la connexion la DB via JNDI On ferme la connexion aprs chaque requte : permet le pooling des connexions ! Lorsque la connexion n'est pas utilise, un autre bean peut l'utiliser ! Pooling ralis par JDBC 2.0 ! Vous tes prt pour le CRUD (Create, Read, Update, Delete) ? En EJB : ejbCreate(), ejbFind(), ejbLoad(), ejbStore, ejbRemove()

AccountBean.java : les mthodes ejb(1)


// EJB-required methods /** Called by Container. Implementation can acquire needed resources. */ public void ejbActivate() { System.out.println("ejbActivate() called."); } /** Removes entity bean data from the database. Corresponds to when client calls home.remove().*/ public void ejbRemove() { System.out.println("ejbRemove() called."); /* Remember that an entity bean class can be used to represent different data instances. * 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. By * retrieving the primary key from the entity context, we know which data instance, keyed * by the PK, that we should delete from the DB. */ AccountPK pk = (AccountPK) ctx.getPrimaryKey(); String id = pk.accountID; PreparedStatement pstmt = null; Connection conn = null; try { /* 1) Acquire a new JDBC Connection */ conn = getConnection(); /* 2) Remove account from the DB*/ pstmt = conn.prepareStatement("delete from accounts where id = ?"); pstmt.setString(1, id);

AccountBean.java : les mthodes ejb(2)


/* 3) Throw a system-level exception if something bad happened. */ if (pstmt.executeUpdate() == 0) { throw new RemoteException("Account " + pk + " failed to be removed from the database"); } } catch (Exception ex) { throw new EJBException(ex.toString()); } finally { /* 4) Release the DB Connection */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) {} try { if (conn != null) conn.close(); } catch (Exception e) {} } } /** Called by Container. Releases held resources for passivation.*/

public void ejbPassivate() { System.out.println("ejbPassivate () called."); }

AccountBean.java : les mthodes ejb(3)


/** Called by the container. public void ejbLoad() { System.out.println("ejbLoad() called."); /* Again, query the Entity Context to get the current Primary Key, so we know which * instance to load. */ AccountPK pk = (AccountPK) ctx.getPrimaryKey(); String id = pk.accountID; PreparedStatement pstmt = null; Connection conn = null; try { /* 1) Acquire a new DB Connection */ conn = getConnection(); /* 2) Get account from the DB, querying by account ID */ pstmt = conn.prepareStatement("select ownerName, balance from accounts where id = ?"); pstmt.setString(1, id); ResultSet rs = pstmt.executeQuery(); rs.next(); ownerName = rs.getString("ownerName"); balance = rs.getDouble("balance"); ... Updates the in-memory entity bean object to reflect the current

* value stored in the database.*/

AccountBean.java : les mthodes ejb(4)


}catch (Exception ex) { throw new EJBException("Account " + pk + " failed to load from database", ex); } finally { /* 3) Release the DB Connection */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) {} try { if (conn != null) conn.close(); } catch (Exception e) {} } } /** Called from the Container. public void ejbStore() { System.out.println("ejbStore() called."); PreparedStatement pstmt = null; Connection conn = null; try { /* 1) Acquire a new DB Connection */ conn = getConnection(); ... Updates the database to reflect the current values of this

* in-memory entity bean instance.*/

AccountBean.java : les mthodes ejb(5)


/* 2) Store account in DB */ pstmt = conn.prepareStatement("update accounts set ownerName = ?, balance = ? where id = ?"); pstmt.setString(1, ownerName); pstmt.setDouble(2, balance); pstmt.setString(3, accountID); pstmt.executeUpdate(); } catch (Exception ex) { throw new EJBException("Account " + accountID + " failed to save to database", ex); } finally { /* 3) Release the DB Connection */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) {} try { if (conn != null) conn.close(); } catch (Exception e) {} } } /** Called by the container. Associates this bean instance with a particular context. We can query * the bean properties which customize the bean here. */ public void setEntityContext(EntityContext ctx) { System.out.println("setEntityContext called"); this.ctx = ctx; }

AccountBean.java : les mthodes ejb(6)


/** Called by Container. Disassociates this bean instance with a particular context environment. */ public void unsetEntityContext() { System.out.println("unsetEntityContext called"); this.ctx = null; } /** Called after ejbCreate(). * as a 'this' argument. */ public void ejbPostCreate(String accountID, String ownerName) { } /** 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. * @return The primary key for this account */ public AccountPK ejbCreate(String accountID, String ownerName) throws CreateException { PreparedStatement pstmt = null; Connection conn = null; try { System.out.println("ejbCreate() called."); this.accountID = accountID; this.ownerName = ownerName; this.balance = 0; /* Acquire DB connection */ conn = getConnection(); Now, the Bean can retrieve its EJBObject from its context, and pass it

AccountBean.java : les mthodes ejb(7)

/* insert the account into the database */ pstmt = conn.prepareStatement("insert into accounts (id, ownerName, balance) values (?, ?, ?)"); pstmt.setString(1, accountID); pstmt.setString(2, ownerName); pstmt.setDouble(3, balance); pstmt.executeUpdate(); /* Generate the Primary Key and return it */ return new AccountPK(accountID); }catch (Exception e) { throw new CreateException(e.toString()); }finally { /* Release DB Connection for other beans */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) {} try { if (conn != null) conn.close(); } catch (Exception e) {} } }

AccountBean.java : les mthodes ejb(8)


/** Finds a Account by its primary Key */ public AccountPK ejbFindByPrimaryKey(AccountPK key) throws FinderException { PreparedStatement pstmt = null; Connection conn = null; try { System.out.println("ejbFindByPrimaryKey(" + key + ") called"); /* Acquire DB connection */ conn = getConnection(); /* Find the Entity in the DB */ pstmt = conn.prepareStatement("select id from accounts where id = ?"); pstmt.setString(1, key.toString()); ResultSet rs = pstmt.executeQuery(); rs.next(); /* No errors occurred, so return the Primary Key */ return key; } catch (Exception e) { throw new FinderException(e.toString()); }finally { /* Release DB Connection for other beans */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) {} try { if (conn != null) conn.close(); } catch (Exception e) {} } }

AccountBean.java : les mthodes ejb(9)


/** Finds a Account by its Name */ public Collection ejbFindByOwnerName(String name) throws FinderException { PreparedStatement pstmt = null; Connection conn = null; Vector v = new Vector(); try { System.out.println("ejbFindByOwnerName(" + name + ") called"); /* Acquire DB connection */ conn = getConnection(); /* Find the primary keys in the DB */ pstmt = conn.prepareStatement("select id from accounts where ownerName = ?"); pstmt.setString(1, name); ResultSet rs = pstmt.executeQuery(); /* Insert every primary key found into a vector */ while (rs.next()) { String id = rs.getString("id"); v.addElement(new AccountPK(id)); } /* Return the vector of primary keys */ return v; } catch (Exception e) { throw new FinderException(e.toString()); }

AccountBean.java : les mthodes ejb(10)


finally { /* Release DB Connection for other beans */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) {} try { if (conn != null) conn.close(); } catch (Exception e) {} } } } // OUF !

AccountBean.java : remarques
JDBC est intelligent lorsqu'on utilise les prepared statements Utilisation de cache et de statistiques sur les reqtes Cf "How Prepared Statements Greatly Improve Performance" sur www.ejbinfo.com

AccountException.java
package examples; /** Exceptions thrown by Accounts */ public class AccountException extends Exception { public AccountException() { super(); } public AccountException(Exception e) { super(e.toString()); } public AccountException(String s) { super(s); } }

Client.java (1)
package examples; import javax.ejb.*; import javax.naming.*; import java.rmi.*; import javax.rmi.*; import java.util.*; /** Sample client code which manipulates a Bank Account Entity Bean. */ public class AccountClient { public static void main(String[] args) throws Exception { Account account = null; try { /* Get a reference to the Account Home Object - the * factory for Account EJB Objects */ Context ctx = new InitialContext(System.getProperties()); Object obj = ctx.lookup("AccountHome"); AccountHome home = (AccountHome) javax.rmi.PortableRemoteObject.narrow(obj, AccountHome.class);

Client.java (2)
System.err.println("Total of all accounts in bank initially = " + home.getTotalBankValue()); /* Use the factory to create the Account EJB Object */ home.create("123-456-7890", "John Smith"); /* Find an account */ Iterator i = home.findByOwnerName("John Smith").iterator(); if (i.hasNext()) { account = (Account) i.next(); } else { throw new Exception("Could not find account"); } /* Call the balance() method, and print it */ System.out.println("Initial Balance = " + account.getBalance()); /* Deposit $100 into the account */ account.deposit(100); /* Retrieve the resulting balance. */ System.out.println("After depositing 100, account balance = " + account.getBalance());

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

Client.java (4)

finally { /* Destroy the Entity permanently */ try { System.out.println("Destroying account.."); if (account != null) { account.remove(); } } catch (Exception e) { e.printStackTrace(); } } }

Descripteur de dploiement (1)


<?xml version="1.0"?> <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'> <ejb-jar> <enterprise-beans> <entity> <ejb-name>Account</ejb-name> <home>examples.AccountHome</home> <remote>examples.Account</remote> <local-home>examples.AccountLocalHome</local-home> <local>examples.AccountLocal</local> <ejb-class>examples.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.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </entity> </enterprise-beans> ...

Descripteur de dploiement (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>

Descripteur spcifique
Change selon le vendeur de container, Configure JNDI, spcifie les noms

La table dans la DataBase


Pour pouvoir excuter cet exemple, il est ncessaire d'avoir cre la table accounts dans une base de donne :
drop table accounts; create table accounts (id varchar(64), ownername varchar(64), balance numeric(18));

Excution, les sorties ct serveur


New Bank Account Entity Bean Java Object created by EJB Container. setEntityContext called ejbHomeGetTotalBankValue() called ejbCreate() called. ejbStore() called. New Bank Account Entity Bean Java Object created by EJB Container. setEntityContext called ejbFindByOwnerName(John Smith) called ejbLoad() called. getBalance() called. ejbStore() called. ejbLoad() called. deposit(100.0) called. ejbStore() called. ejbLoad() called. getBalance() called. ejbStore() called. ejbHomeGetTotalBankValue() called ejbFindByPrimaryKey(123-456-7890) called ejbLoad() called. getBalance() called. ejbStore() called. ejbLoad() called. withdraw(150.0) called. ejbStore() called. ejbLoad() called. ejbRemove() called.

Excution, les sorties ct client


Total of all accounts in bank initially = 1200000.0 Initial Balance = 0.0 After depositing 100, account balance = 100.0 Total of all accounts in bank now = 1200100.0 Found account with ID 123-456-7890. Balance = 100.0

Now trying to withdraw $150, which is more than is currently available. This should generate an exception.. Caught exception! examples.AccountException: Your balance is 100.0! 150.0! Destroying account.. You cannot withdraw

BMP entity bean : cycle de vie

Container-Managed Persistent Entity Beans (CMP)


Michel Buffa (buffa@unice.fr), UNSA 2002

CMP entity beans


Le second type d'entity bean, Le container assure l'implmentation de toute la logique d'accs aux donnes, Ceci simplifie grandement le dveloppement !
Moins de bugs, Code plus court, Plus de performance ?! Comparer avec les garbage collectors Attention au choix du container

Les CMP : un rel besoin


Le vendeur de beans ne veut pas tre dpendant du moyen assur pour raliser la persistance. Il distribue ses beans, sans le source le plus souvent Le client dcide o il va stocker les donnes CMP rpond au besoin de ce dcoupage .NET dit le contraire !

Les CMP : dcoupage par gnration de sous-classe


Le dveloppeur crit son bean CMP, sans logique donnes (pas de JDBC) Le container gnre le code JDBC dans une sous-classe de la classe fournie par le dveloppeur. Un bean CMP = la classe du dveloppeur + la sous-classe gnre par le container. Dcoupage propre !

Les CMP : pas de dclaration d'attributs !


Le container gre la persistance sa manire,
Par exemple, mettre des marqueurs sur les attributs pour voir s'ils ont chang, s'il faut synchroniser la DB, etc Bref, pour viter du code sale, EJB 2.0 fait carrment sauter la dclaration des attributs dans le code fourni par le dveloppeur !

Les attributs sont dclars dans la sous-classe gnre par le container ! Mais alors, comment y accde-t-on ? O les dclare-t-on ?

Les CMP : pas de dclaration d'attributs !


BMP
public class AccountBean implements EntityBean { public String accountID; public String ownerName; public double balance; ...methods... } // PK

CMP
// CMP Subclass public class AccountBeanSubClass extends AccountBean { public String accountID; public String ownerName; public double balance; ...methods... } // PK

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 dclars les attributs // PK

CMP : mais alors, que mettre dans la classe du bean ?


Problme : on ne peut avoir de get/set car on n'a pas accs 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 : schma de persistance abstrait


Le container sait quoi gnrer dans la sous-classe grce aux mthodes abstraites de la classe du bean, Mais aussi grce 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 requtes !


EJB 2.0 fournit EJB QL, un langage de requtes! 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 requtes !


Avec CMP, on crit la requte EJB-QL correspondant la mthode finder dans le descripteur du bean Ex de requte EJB-QL qui slectionne tous les comptes bancaires
SELECT OBJECT(a) FROM Account AS a WHERE a.accountID IS NOT NULL

Ex de requte EJB-QL qui slectionne tous les comptes bancaires dont le solde est > paramtre minimum de ejbFindBigAccounts(int minimum)
SELECT OBJECT(a) FROM Account AS a WHERE a.balance > ?1

CMP : quelques attributs quand mme


Remarque : tous les champs n'ont pas besoin d'tre persistants Les contextes sont dclars normalement dans la classe du bean par exemple Le container ne s'occupera pas des champs dclars dans la classe du bean.

CMP : dveloppement/dploiement

Mthodes ejbSelect()
Les beans CMP peuvent avoir des mthodes ejbSelect() Ces mthodes sont des finders usage interne, non exposs aux clients du bean, Utile lorsqu'on a des entity beans CMP qui ont des relations avec des donnes externes, comme d'autres entity beans. Par exemple : ejbHomeGetTotalBankValue() que nous avons vu dans l'exemple BMP
Avec BMP, cette mthode faisait un SELECT, Avec CMP, on n'a pas crire de requte SQL, elle appellera la place une mthode ejbSelect() On indiquera au container quelle requte EJB-QL associer ejbSelect()

Mthodes 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 mthodes ejbSelect() peuvent renvoyer des entity beans. Mais elles peuvent aussi renvoyer des attributs grs par le container ! Dans l'exemple, c'est une collection de valeurs double qui est renvoye.

Mthodes ejbSelect()
La requte EJB-QL associe chaque mthode finder se trouve dans le descripteur de dploiement. 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 !

CMP : un exemple
Une ligne de produits gnriques

Product.java : l'interface remote


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

ProductLocal.java : l'interface locale


package examples; import javax.ejb.*; /** These are the public business methods of ProductBean. This local interface is * what local clients operate on when they interact with beans. The EJB container * will implement this interface; the implemented object is called the EJB local * Object, which delegates invocations to instances of the entity bean class. */ public interface ProductLocal extends EJBLocalObject { public String getName(); public void setName(String name); public String getDescription(); public void setDescription(String description); public double getBasePrice(); public void setBasePrice(double price); public String getProductID(); }

ProductHome.java : l'interface home (1)


package examples; import javax.ejb.*; import java.rmi.RemoteException; import java.util.Collection; /** This is the home interface for Product. * EJB container. * factory for EJB Objects. * One create() method is in this Home Interface, which corresponds to the * ejbCreate() method in the bean class. */ 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. */ Product create(String productID, String name, String description, double basePrice) throws CreateException, RemoteException; ... This interface is implemented by the

The implemented object is called the Home Object, and serves as a

ProductHome.java : l'interface home (2)


... // Finder methods. // container tools. public Product findByPrimaryKey(String key) throws FinderException, RemoteException; public Collection findByName(String name) throws FinderException, RemoteException; public Collection findByDescription(String description) throws FinderException, RemoteException; public Collection findByBasePrice(double basePrice) throws FinderException, RemoteException; public Collection findExpensiveProducts(double minPrice) throws FinderException, RemoteException; public Collection findCheapProducts(double maxPrice) throws FinderException, RemoteException; public Collection findAllProducts() throws FinderException, RemoteException; } These are implemented by the container. You can customize the // functionality of these methods in the deployment descriptor through EJB-QL and

ProductLocalHome.java : interface local home


package examples; import javax.ejb.*; import java.util.Collection; public interface ProductHome extends EJBLocalHome { Product create(String productID, String name, String description, double basePrice) throws CreateException; // Finder methods. public Product findByPrimaryKey(ProductPK key) throws FinderException; public Collection findByName(String name) throws FinderException; public Collection findByDescription(String description) throws FinderException; public Collection findByBasePrice(double basePrice) throws FinderException; public Collection findExpensiveProducts(double minPrice) throws FinderException; public Collection findCheapProducts(double maxPrice) throws FinderException; public Collection findAllProducts() throws FinderException; }

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 srialisable. Comme le container assure la persistance, les attributs doivent avoir t dclar dans le descripteur ! Il vaut mieux utiliser une classe pour la cl primaire, plutt que dclarer 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 trs court ! Ce bean est bien plus complexe que l'exemple BMP dj tudi, qui tait si long !
Nombreuses mthodes finder, Plus d'attributs persistants, Taille 40% infrieure, au moins ! Pas de JDBC, moins de risque d'erreurs

ejb-jar.xml : le descripteur de dploiement(1)


<?xml version="1.0"?> <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_2_0.dtd"> <ejb-jar> <enterprise-beans> <entity> <ejb-name>Product</ejb-name> <home>examples.ProductHome</home> <remote>examples.Product</remote> <local-home>examples.ProductLocalHome</local-home> <local>examples.ProductLocal</local> <ejb-class>examples.ProductBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>examples.ProductPK</prim-key-class> <reentrant>False</reentrant> <cmp-version>2.x</cmp-version> ...

ejb-jar.xml : le descripteur de dploiement(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 dploiement(3)


<query> <query-method> <method-name>findByName</method-name> <method-params> <method-param>java.lang.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.lang.String</method-param> </method-params> </query-method> ...

ejb-jar.xml : le descripteur de dploiement(4)


... <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> ...

ejb-jar.xml : le descripteur de dploiement(5)


... <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-jar.xml : le descripteur de dploiement(6)


... <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.xml : le descripteur de dploiement(7)


... <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 dploiement : remarques


Ouch, il est long ! Mais il est simple ! En plus, il est souvent gnr par des outils (IDE, wizards)

Descripteur spcifique
Dans le cas o on utilise un SGBD relationnel pour la persistance, il faut indiquer le mapping Objet/Relationnel au container.. En gros, associer les attributs du bean avec des noms de colonnes Si la table n'existe pas, le container peut la crer automatiquement, Si la table existe, les IDE proposent le plus souvent des wizards pour vous aider.

Client.java (1)
package examples; import javax.ejb.*; import javax.naming.*; import java.rmi.*; import javax.rmi.PortableRemoteObject; import java.util.*; /** Client test application on a CMP Entity Bean, Product.*/ public class ProductClient { public static void main(String[] args) throws Exception { ProductHome home = null; try { /* Get a reference to the Product Home Object - the factory for Product EJB * Objects */ Context ctx = new InitialContext(System.getProperties()); home = (ProductHome) PortableRemoteObject.narrow(ctx.lookup("ProductHome"), ProductHome.class);

Client.java (2)
/* Use the factory to create the Product EJB Object*/ home.create("123-456-7890", "P5-350", "350 Mhz Pentium", 200); home.create("123-456-7891", "P5-400", "400 Mhz Pentium", 300); home.create("123-456-7892", "P5-450", "450 Mhz Pentium", 400); home.create("123-456-7893", "SD-64", "64 MB SDRAM", 50); home.create("123-456-7894", "SD-128", "128 MB SDRAM", 100); home.create("123-456-7895", "SD-256", "256 MB SDRAM", 200);

/* Find a Product, and print out it's description */ Iterator i = home.findByName("SD-64").iterator(); System.out.println("These products match the name SD-64:"); while (i.hasNext()) { Product prod = (Product) PortableRemoteObject.narrow(i.next(), Product.class); System.out.println(prod.getDescription()); }

Client.java (3)
/* Find all products that cost $200 */ System.out.println("Finding all products that cost $200"); i = home.findByBasePrice(200).iterator(); while (i.hasNext()) { Product prod = (Product) PortableRemoteObject.narrow(i.next(), Product.class); System.out.println(prod.getDescription()); } } catch (Exception e) { e.printStackTrace(); } finally { if (home != null) { System.out.println("Destroying products.."); /* Find all the products */ Iterator i = home.findAllProducts().iterator(); while (i.hasNext()) { try { Product prod = (Product) PortableRemoteObject.narrow(i.next(), Product.class);

Client.java (4)
if (prod.getProductID().startsWith("123")) { prod.remove(); } } catch (Exception e) { e.printStackTrace(); } } } } } }

Client.java : rsultats
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..

Cycle de vie d'un bean CMP

Message-Driven Beans
Michel Buffa (buffa@unice.fr), UNSA 2002

Message-Driven Beans
Nouveaut EJB 2.0, Messaging = moyen de communication lger, compar RMI-IIOP, Pratique dans de nombreux cas, Message-Driven beans = beans accessibles par messaging asynchrone.

Message-Driven Beans : motivation


Performance
Un client RMI-IIOP attend pendant que le serveur effectue le traitement d'une requte,

Fiabilit
Lorsqu'un client RMI-IIOP parle avec un serveur, ce dernier doit tre en train de fonctionner. S'il crashe, ou si le rseau crashe, le client est coinc.

Pas de broadcasting !
RMI-IIOP limite les liaisons 1 client vers 1 serveur

Messaging
C'est comme le mail ! Ou comme si on avait une troisime personne entre le client et le serveur !

Messaging
A cause de ce "troisime homme" les performances ne sont pas toujours au rendez-vous ! Message Oriented Middleware (MOM) est le nom donn aux middlewares qui supportent le messaging.
Tibco Rendezvous, IBM MQSeries, BEA Tuxedo/Q, Microsoft MSMQ, Talarian SmartSockets, Progress SonicMQ, Fiorano FioranoMQ, Ces produits fournissent : messages avec garantie de livraison, tolrance aux fautes, load-balancing des destinations, etc

The Java Message Service (JMS)


Les serveurs MOM sont pour la plupart propritaires : pas de portabilit des applications ! JMS = un standard pour normaliser les changes entre composant et serveur MOM,
Une API pour le dveloppeur, Un Service Provider Interface (SPI), pour rendre connecter l'API et les serveurs MOM, via les drivers JMS

JMS : Messaging Domains


Avant de faire du mesaging, 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, 1 consommateur

JMS : les tapes


1.

Localiser le driver JMS


lookup JNDI. Le driver est une connection factory

2.

Crer une connection JMS


obtenir une connection partir de la connection factory

3.

Crer une session JMS


Il s'agit d'un objet qui va servir recevoir et envoyer des messages. On l'obtient partir de la connection.

4.

Localiser la destination JMS


Il s'agit du canal, de la chane tl ! Normalement, c'est rgl par le dployeur. On obtient la destination via JNDI.

5.

Crer un producteur ou un consommateur JMS


Utiliss pour crire ou lire un message. On les obtient partir de la destination ou de la session.

6.

Envoyer ou recevoir un message

JMS : les tapes

JMS : les interfaces

JMS : exemple de code (1)


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

JMS : exemple de code (2)

// 3: Use Connection to create session TopicSession session = connection.createTopicSession( false, Session.AUTO_ACKNOWLEDGE); // 4: Lookup Destination (topic) via JNDI Topic topic = (Topic) ctx.lookup("testtopic"); // 5: Create a Message Producer TopicPublisher publisher = session.createPublisher(topic); // 6: Create a text message, and publish it TextMessage msg = session.createTextMessage(); msg.setText("This is a test message."); publisher.publish(msg); } }

Intgrer JMS et les EJB


Pourquoi crer un nouveau type d'EJB ? Pourquoi ne pas avoir dlgu le travail un objet spcialis ? Pourquoi ne pas avoir augment les caractristiques des session beans ? Parce que ainsi on peut bnficier de tous les avantages dj rencontrs : cycle de vie, pooling, descripteurs spcialiss, code simple

Qu'est-ce qu'un Message-Driven Bean ?


Un EJB qui peut recevoir des messages
Il consomme des messages depuis les queues ou topics, envoys par les clients JMS

Qu'est-ce qu'un Message-Driven Bean ?


Un client n'accde pas un MDB via une interface, il utilise l'API JMS, Un MDB n'a pas d'interface Home, Local Home, Remote ou Local, Les MDB possdent une seule mthode, faiblement type : onMessage()
Elle accepte un message JMS (BytesMessage, ObjectMessage, TextMessage, StreamMessage ou MapMessage) Pas de vrification de types la compilation. Utiliser instanceof au run-time pour connatre le type du message.

Les MDB n'ont pas de valeur de retour


Ils sont dcoupls des producteurs de messages.

Qu'est-ce qu'un Message-Driven Bean ?


Pour envoyer une rponse l'expditeur : plusieurs design patterns Les MDB ne renvoient pas d'exceptions au client (mais au container), Les MDB sont stateless Les MDB peuvent tre des abonns durables ou nondurables (durable or nondurable subscribers) un topic
Durable = reoit tous les messages, mme si l'abonn est inactif, Dans ce cas, le message est rendu persistant et sera dlivr lorsque l'abonn sera de nouveau actif. Nondurable = messages perdus lorsque abonn inactif.

Qu'est-ce qu'un Message-Driven Bean ?


Le consommateur (celui qui peut les dtruire) des messages est en gnral le Container
C'est lui qui choisit d'tre durable ou non-durable, S'il est durable, les messages rsistent au crash du serveur d'application.

Dvelopper un Message-Driven Bean


Les MDBs doivent implmenter
public interface javax.jms.MessageListener { public void onMessage(Message message); } public interface javax.ejb.MessageDrivenBean extends EnterpriseBean { public void ejbRemove() throws EJBException; public void setMessageDrivenContext(MessageDrivenContext ctx) throws EJBException; }

La classe d'implmentation doit fournir une mthode ejbCreate() qui renvoit void et qui n'a pas d'arguments.

Dvelopper un Message-Driven Bean


Mthodes qui doivent tre implmentes
onMessage(Message) Invoque chaque consommation de message Un message par instance de MBD, pooling assur par le container ejbCreate() Rcuprer les rfrences aux ressources, initialiser des attributs ejbRemove() Librer les ressources setMessageDrivenContext(MessageDrivenContext) Appele avant ejbCreate, sert rcuprer le contexte. Ne contient que des mthodes lies aux transactions

Dvelopper un Message-Driven Bean

Un exemple simple
Un MDB qui fait du logging, c'est dire affiche des messages de textes l'cran chaque fois qu'il consomme un message.
Utile pour dbugger.

Rappel : pas d'interfaces !

La classe du bean
package examples; import javax.ejb.*; import javax.jms.*; /** Sample Message-Driven Bean */ public class LogBean implements MessageDrivenBean, MessageListener { protected MessageDrivenContext ctx; /** Associates this Bean instance with a particular context. */ public void setMessageDrivenContext(MessageDrivenContext ctx) { this.ctx = ctx; } /** Initializes the bean */ public void ejbCreate() { System.err.println("ejbCreate()"); } ...

... /** Our one business method */ public void onMessage(Message msg) { TextMessage tm = (TextMessage) msg; try { String text = tm.getText(); System.err.println("Received new message : " + text); } catch(JMSException e) { e.printStackTrace(); } } /** Destroys the bean */ public void ejbRemove() { System.err.println("ejbRemove()"); } }

Le descripteur de dploiement
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_2_0.dtd"> <ejb-jar> <enterprise-beans> <!-For each message-driven bean that is located in an ejb-jar file, you have to define a <message-driven> entry in the deployment descriptor. --> <message-driven> <!-- The nickname for the bean could be used later in DD --> <ejb-name>Log</ejb-name> <!-- The fully qualified package name of the bean class --> <ejb-class>examples.LogBean</ejb-class> <!-- The type of transaction supported (see Chapter 10) --> <transaction-type>Container</transaction-type> <!-- Whether I'm listening to a topic or a queue --> <message-driven-destination> <destination-type>javax.jms.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'apparat pas dans le descripteur !

C'est fait exprs pour rendre les MDB portables et rutilisables. L'information se trouve dans le descripteur spcifique

Exemple de descripteur spcifique, tir d'un autre exemple (Borland)


<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ejb-jar PUBLIC "-//Borland Software Corporation//DTD Enterprise JavaBeans 2.0//EN" "http://www.borland.com/devsupport/appserver/dtds/ejb-jar_2_0-borland.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.naming.*; import javax.jms.*; import java.util.*; public class Client { public static void main (String[] args) throws Exception { // Initialize JNDI Context ctx = new InitialContext(System.getProperties()); // 1: Lookup ConnectionFactory via JNDI TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("javax.jms.TopicConnectionFactory"); // 2: Use ConnectionFactory to create JMS connection TopicConnection connection = factory.createTopicConnection();

Le client (2)

// 3: Use Connection to create session TopicSession session = connection.createTopicSession( false, Session.AUTO_ACKNOWLEDGE); // 4: Lookup Destination (topic) via JNDI Topic topic = (Topic) ctx.lookup("testtopic"); // 5: Create a Message Producer TopicPublisher publisher = session.createPublisher(topic); // 6: Create a text message, and publish it TextMessage msg = session.createTextMessage(); msg.setText("This is a test message."); publisher.publish(msg); } }

Concepts avancs
Transactions et MBD,
La production et la consommation du message sont dans deux transactions spares

Scurit,
Les MDB ne reoivent pas les informations de scurit du producteur avec le message. On ne peut pas effectuer les oprations classiques de scurit sur les EJB.

Load-Balancing,
Modle idal : les messages sont dans une queue et ce sont les MDB qui consomment, d'o qu'ils proviennent. Comparer avec les appels RMI-IIOP pour les session et entity beans, ou on ne peut que faire des statistiques

Concepts avancs
Consommation duplique 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 avancs

Piges !
Ordre des messages
Le serveur JMS ne garantit pas l'ordre de livraison des messages.

L'appel ejbRemove() n'est pas garanti, comme pour les session beans stateless
A cause du pooling, En cas de crash.

Messages empoisonns (poison messages)


A cause des transactions un message peut ne jamais tre consomm

Piges !
Messages empoisonns (poison messages)
A cause des transactions un message peut ne jamais tre consomm

MDB empoisonn !
package examples;

import javax.ejb.*; import javax.jms.*;

public class PoisonBean implements MessageDrivenBean, MessageListener {

private MessageDrivenContext ctx;

public void setMessageDrivenContext(MessageDrivenContext ctx) { this.ctx = ctx; } public void ejbCreate() {} public void ejbRemove() {} ...

MDB empoisonn !
... public void onMessage(Message msg) try { System.out.println("Received msg " + msg.getJMSMessageID()); // Let's sleep a little bit so that we don't see rapid fire re-sends of the message. Thread.sleep(3000); {

// We could either throw a system exception here or // manually force a rollback of the transaction. ctx.setRollbackOnly(); } catch (Exception e) { e.printStackTrace(); } } }

MDB empoisonn !
Solutions
Ne pas lever d'exception, Utiliser des transactions gres par le bean, non par le container, Certains serveurs peuvent configurer une "poison message queue" ou possder un paramtre "nb max retries"

Comment renvoyer des rsultats l'expditeur du message ?


A faire la main ! Rien n'est prvu !

Comment renvoyer des rsultats l'expditeur du message ?


Nanmoins, des problmes se posent si le client est lui-mme 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 rponses, au niveau du serveur JMS.

Comment renvoyer des rsultats l'expditeur du message ?

Comment renvoyer des rsultats l'expditeur du message ?


D'autres solutions existent JMS propose deux classes javax.jms.QueueRequestor et javax.jms.TopicRequestor qui implmentent une pattern simple question/rponse Solution bloquante, pas de gestion de transactions Le futur : invocation de mthode asynchrone

Ajouter de la fonctionnalit aux beans


Michel Buffa (buffa@unice.fr), UNSA 2002

Dans ce chapitre, nous allons voir


Comment appeler un bean depuis un autre bean, Utiliser les proprits d'environnement du bean au runtime, Comment utiliser les resources factories (JDBC, JMS), Utiliser le modle de scurit EJB, Comment utiliser les EJB object handles et EJB home handles.

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), etc

On utilise JNDI comme pour n'importe quel client


1. 2. 3. 4.

Lookup du home object de l'EJB cible via JNDI, Appel de create() sur le home object, Appel de mthodes business, Appel de remove sur le ejb object.

Appeler un bean depuis un autre bean


Comment indiquer les paramtres d'initialisation JNDI (driver, etc) ? Pas besoin, le container les a dj initialiss
On les rcupres via un InitialContext
//Obtain the DEFAULT JNDI initial context by calling the //no-argument constructor Context ctx =new InitialContext(); //Look up the home interface Object result =ctx.lookup("java:comp/env/ejb/CatalogHome"); //Convert the result to the proper type,RMI-IIOP style CatalogHome home =(CatalogHome) javax.rmi.PortableRemoteObject.narrow( result,CatalogHome.class); //Create a bean Catalog c =home.create(...);

Comprendre les rfrences EJB


Dans le code prcdent, la localisation JNDI du bean recherch est java:comp/env/ejb.
Recommand par la spcification EJB. Peut nanmoins changer si le serveur JNDI a une configuration bizarre. Le dployeur ne peut pourtant pas changer votre code !

EJB rfrences = dans le descripteur


Permet au dployeur de vrifier que tous les beans rfrences par un autre bean sont bien dploys et enregistrs avec les noms JNDI corrects.

Comprendre les rfrences EJB


... <enterprise-beans> <!-Here,we define our Catalog bean. We use the "Catalog"ejb-name.We will use this below. --> <session> <ejb-name>Catalog</ejb-name> <home>examples.CatalogHome</home> ... </session> <session> <ejb-name>Pricer</ejb-name> <home>examples.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 rfrences EJB


<!-The nickname that Pricer uses to look up Catalog.We declare it so the deployer knows to bind the Catalog home in java:comp/env/ejb/CatalogHome.This may not correspond to the actual location to which the deployer binds the object via the container tools.The deployer may set up some kind of symbolic link to have the nickname point to the real JNDI location. --> <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.CatalogHome</home> <!--The Catalog remote interface class --> <remote>examples.Catalog</remote> <!--(Optional)the Catalog ejb-name --> <ejb-link>Catalog</ejb-link> </ejb-ref> </session> </enterprise-beans>

Resources factories (JDBC, JMS)


Comment accder des ressources extrieures l'EJB ?
Sources de donnes ? JMS driver ?

Pour utiliser une resource factory, il faut d'abord la localiser


//Obtain the initial JNDI context Context initCtx =new InitialContext(); //Perform JNDI lookup to obtain resource factory javax.sql.DataSource ds =(javax.sql.DataSource) initCtx.lookup("java:comp/env/jdbc/ejbPool");

Resources factories (JDBC, JMS)


La localisation java:comp/env/jdbc/ejbPool
Les informations relles doivent se trouver dans le descripteur (driver JDBC, URL de la datasource, etc)

Resources factories (JDBC, JMS)


<enterprise-beans> <session> <ejb-name>Catalog</ejb-name> <home>examples.CatalogHome</home> <!-- This element indicates a resource factory reference --> <resource-ref> <description> This is a reference to a JDBC driver used within the Catalog bean. </description> <!-- The JNDI location that Catalog uses to look up the JDBC driver. 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> <!-- The resource factory class --> <res-type>javax.sql.DataSource</res-type> <!-- Security for accessing the resource factory. Can either be "Container" or Application". --> <res-auth>Container</res-auth> <!-- Whether connections should be shared with other clients in the different transactions --> <res-sharing-scope>Sharable</res-sharing-scope> </resource-ref>

Resources factories (JDBC, JMS)


Remarque sur <res-auth>..</res-auth> L'accs la datasource peut ncessiter des autorisations (login, password),
On peut passer ces paramtres dans l'application, Ou dans le descripteur (c'est donc le container qui va grer l'authentification) Cas le plus courant !

Le modle de scurit EJB


Deux mesures de scurit que les clients doivent satisfaire lorsqu'on ajoute la scurit un systme EJB
1. 2.

Le client doit s'authentifier Le client doit tre autoris

Le modle de scurit EJB


1.

Le client doit s'authentifier


Le mcanisme d'authentification vrifie que le client est bien celui qu'il prtend tre, A l'aide de login/password valids auprs d'une base de donnes, de LDAP, etc Une fois authentifi, on lui associe une security identity pour le reste de la session.

2.

Le client doit tre autoris


Une fois authentifi, il doit avoir la permission d'effectuer les oprations dsires. Par exemple tout le monde peut faire des offres de prts, seul le banquier peut les accepter.

Etape 1 : l'authentification
Avec EJB 1.0 et 1.1, pas de mcanisme d'authentification portable EJB 2.0 propose un modle portable et robuste
A l'aide de Java Authentification and Authorization Service (JAAS) : une API J2EE standard.

Prsentation de JAAS
JAAS est implmente par le serveur d'application JAAS permet d'utiliser de manire transparente pour le dveloppeur de bean n'importe quel systme d'authentification sous-jacent.
Login/password, LDAP, certificats, simple lookup dans une BD, etc

Prsentation de JAAS

Quelques commentaires
Les informations fournies par le client, dans le cas d'un client web peuvent tre de 4 types
1. 2. 3.

4.

Basic authentification : login password en texte (idem .htaccess), 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-mme. Le serveur web fait la vrif partir d'un password qu'il lui-mme de son ct. Certificate authentification : protocole X509

Architecture JAAS

Exemple de code JAAS


Cet exemple montre un client qui s'authentifie avant d'appeler la mthode "hello world" d'un bean. Si le password n'est pas correct, une exception est leve

HelloClient.java
package examples; import javax.naming.*; import javax.security.auth.*; import javax.security.auth.callback.*; import javax.security.auth.login.*; import javax.rmi.PortableRemoteObject; public class HelloClient { public static void main(String [] args))throws Exception { /* Authenticate via JAAS */ LoginContext loginContext =new LoginContext("Hello Client"); loginContext.login(); /* Retrieve the logged-in subject */ Subject subject =loginContext.getSubject(); /* Perform business logic while impersonating the authenticated subject */ CallHelloWorld action =new CallHelloWorld(); String result =(String)Subject.doAs(subject,action); /* Print the return result from the business logic */ System.out.println(result); } }

PasswordConfig.java (1)
package examples; import java.util.Hashtable; import javax.security.auth.login.*; /** Sample configuration class for JAAS user authentication. This class is useful because it can be rewritten to use different login modules without affecting client code. For example,we could have a login module that did username/password authentication,and another that did public/private key certificate authentication.*/ public class PasswordConfig extends Configuration { /** A configuration class must have a no-argument constructor */ public PasswordConfig(){}

PasswordConfig.java (2)
/** This method chooses the proper login module. */ public AppConfigurationEntry [] getAppConfigurationEntry(String applicationName) { /* Return the one login module we ve written,which uses username/password authentication. -The "REQUIRED" flag says that we require that this login module succeed for authentication. -The new hashtable is a hashtable of options that our login module will receive. For example,we might define an option that turns debugging on.Our login module would inspect this hashtable and start logging output.*/ AppConfigurationEntry []loginModules = new AppConfigurationEntry [1]; loginModules[0] = new AppConfigurationEntry("examples.PasswordLoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, new Hashtable()); return loginModules; } /** Refresh and reload the Configuration object by readingall of the login configurations again.*/ public void refresh(){} }

PasswordLoginModule.java (1)
package examples; import java.util.*; import javax.naming.Context; import javax.security.auth.*; import javax.security.auth.callback.*; import javax.security.auth.login.*; import javax.security.auth.spi.*; /** Sample login module that performs password authentication. The purpose of this class is to actually go out and perform the authentication. */ public class PasswordLoginModule implements LoginModule { private Subject subject = null; /** Initializes us.We set ourselves to the particular subject which we will later authenticate. */ public void initialize(Subject subject, CallbackHandler callbackHandler,Map sharedState, Map options) { this.subject =subject; }

PasswordLoginModule.java (2)
/** This method authenticates the user.It is called when the client tries to login in. Our method implementation contains the vendor-specific way to access our permanent storage of usernames and passwords. Note that while this code is not portable,it is 100% hidden from your application code behind the LoginModule. The intention is that you develop a different LoginModule for each J2EE server. In this case, BEA has provided us with a helper class that talks JNDI to the Weblogic server,and the server then goes to whatever the currently configured security realm is, such as a file,RDBMS,or LDAP server.*/ public boolean login()throws LoginException { try { /* Authenticate the user s credentials,populating Subject Note:In a real application,we would not hardcode the username and ^p password. Rather,we would write a reusable LoginModule that would work with any username and password. We would then write a special callback handler that knows how to interact with the user,such as prompting the user for a password. We would then call that callback handler here. */ weblogic.jndi.Environment env = new weblogic.jndi.Environment(System.getProperties());

PasswordLoginModule.java (3)
env.setSecurityPrincipal("guest"); env.setSecurityCredentials("guest"); weblogic.security.auth.Authenticate.authenticate(env,subject); /* Return that we have successfully authenticated the subject* / return true; } catch (Exception e){ throw new LoginException(e.toString()); } } /** This method is called if the overall authentication succeeded (even if this particular login module failed). 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 commit()throws LoginException { return true; }

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 dfinissant la police de scurit pour le bean (security policies) Deux manire de faire
1.

2.

Par programmation On effectue les tests dans le code du bean Par autorisation dclarative Le container effectue les tests

Rles de scurit (security roles)


Rle de scurit = une collection d'identits pour le client Un client est autoris effectuer une opration
Son identit doit tre dans le bon rle de scurit pour cette opration, Le dployeur de beans a la responsabilit d'associer les identits et les rles de scurit aprs que vous ayez crit le bean, Grande portabilit et flexibilit.

Autorisation par programmation


tape 1 : crire la logique de scurit
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 : dcrire les rles de scurit abstraits que le bean va utiliser
Par exemple indiquer que le bean a un rle "administrator", On indique ceci dans le descripteur de dploiement.

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 rles de scurit abstraits avec des rles concrets (actual)
Autre niveau d'indirection, permet au dployeur de beans de renommer les rles

Autorisation par programmation


... <enterprise-beans> <session> <ejb-name>EmployeeManagement</ejb-name> <home>examples.EmployeeManagementHome</home> ... <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> <!-- Here we link what we call "administrators"above,to a real security-role,called "admins",defined below --> <role-link>admins</role-link> </security-role-ref> ... </session> <assembly-descriptor> ...

Autorisation par programmation


<!-This is an example of a real security role. --> <security-role> <description> This role is for personnel authorized to perform employee administration. </description> <role-name>admins</role-name> </security-role> ... </assembly-descriptor> </enterprise-beans> ...

Autorisation dclarative
Tout se passe dans le descripteur, au dploiement.
Le container fait tout le travail !

tape 1 : dclarer les permissions associes aux mthodes du bean que l'on dsire scuriser
Le container gnrera le code qui fera les vrifications ncessaires dans l'EJB home et dans l'EJB object

Exemple de dclaration d'autorisation (1)


<assembly-descriptor> <!-- You can set permissions on the entire bean. 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> ...

Exemple de dclaration d'autorisation (2)


<! You can set permissions on a method level. Example: Allow role "managers"to call method "modifySubordinate()"and "modifySelf()". --> <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> ...

Exemple de dclaration d'autorisation (3)


<!-- If you have multiple methods with the same name but that take different parameters,you can even set permissions that distinguish between the two. 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 dclaration d'autorisation (4)


<!-This is the list of methods that we don t want ANYONE to call. Useful if you receive a bean from someone with methods that you dont need. --> <exclude-list> <description> We don t have a 401k plan,so we dont support this method. </description> <method> <ejb-name>EmployeeManagement</ejb-name> <method-name>modify401kPlan</method-name> <method-params>String</method-params> </method> </exclude-list> ... </assembly-descriptor> ...

Autorisation dclarative
tape 2 : dclarer les rles de scurit
Mme mthode que pour les autorisation par programmation On les dclare et on donne une description (optionnelle) pour le deployeur.

Dclarer les rles de scurit


<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> ... </assembly-descriptor>

Que choisir ? Dclarative ou par programmation ?


Dans un monde idal, on utiliserait tout le temps la mthode dclarative
Externalisation de la politique de scurit, Plus facile maintenir et ajuster, Le travail du dployeur, pas du dveloppeur !

Malheureusement, dans la spcification EJB 2.0 il manque encore


La gestion de la scurit par instance, Ex : un bean banquier ne peut modifier que des instances de comptes bancaires dont le solde est infrieur 50.000 francs. (seul le chef peut manipuler les comptes bien fournis!) Dans ce cas, recourir la gestion par programmation.

Propagation de la scurit
Un client a pass tous les tests de scurit pour appeler le bean A. La mthode de A qu'il appelle appelle une mthode d'un bean B, Le client doit-il encore passer les tests de scurit pour B ? En coulisse, le container gre un contexte de scurit (Security Context), qu'il passe de stub et skeleton, d'appel de mthode en appel de mthode

Propagation de la scurit
<enterprise-beans> <session> <ejb-name>EmployeeManagement</ejb-name> <home>examples.EmployeeManagementHome</home> <security-identity> <run-as> <role-name>admins</role-name> </run-as> </security-identity> </session> <assembly-descriptor> ... <security-role> <description> This role is for personnel authorized to perform employee Administration. </description> <role-name>admins</role-name> </security-role> ... </assembly-descriptor> </enterprise-beans>

Un mot sur les Message-Driven Beans


Pas de gestion d'autorisation pour les MDB, ni dclarative, ni par programmation Les MDB ne reoivent pas d'appel de mthode par RMI-IIOP, ils reoivent des messages, Ces messages ne contiennent pas d'information lies la scurit (credentials) Un MDB ne peut pas non plus propager un contexte de scurit qui n'existe pas, Ils peuvent nanmoins avoir une identit lorsqu'ils appellent d'autres beans.

Comprendre les EJB Object Handles


Dans certaines applications, le client d'un bean peut se dconnecter, puis se reconnecter plus tard en retrouvant le bean dans l'tat ! Exemple : un caddy reprsent par un session bean stateful
le client dcide de se dconnecter lorsqu'il se reconnecte il veut retrouver son caddy dans l'tat !

Comprendre les EJB Object Handles


La spcification EJB fournit un outil particulier pour grer ce genre de situations : l'EJB object handles
C'est un proxy vrs un EJB object, Longue dure de vie,

Exemple d'utilisation d'un EJB Object Handle


//First,get the EJB object handle from the EJB object. javax.ejb.Handle myHandle =myEJBObject.getHandle(); // Next, serialize myHandle,and then save it in permanent storage. ObjectOutputStream stream =...; stream.writeObject(myHandle); // time passes... When we want to use the EJB object again, deserialize // the EJB object handle ObjectInputStream stream =...; Handle myHandle =(Handle) stream.readObject(); // Convert the EJB object handle into an EJB object MyRemoteInterface myEJBObject =(MyRemoteInterface) javax.rmi.PortableRemoteObject.narrow(myHandle.getEJBObject(), MyRemoteInterface.class); // Resume calling methods again myEJBObject.callMethod();

Variante : les EJB Home Handles


Idem, mais pour rendre persistant une rfrence vers le home object d'un bean, Peu utiliss

Exemple d'utilisation d'un EJB Home Handle


//First,get the EJB home handle from the home object. javax.ejb.HomeHandle homeHandle =myHomeObject.getHomeHandle(); //Next,serialize the home handle,and then save it in permanent storage. ObjectOutputStream stream =...; stream.writeObject(homeHandle); // time passes...When we want to use the home object again,deserialize the home // handle ObjectInputStream stream =...; javax.ejb.HomeHandle homeHandle =(HomeHandle)stream.readObject(); // Convert the home object handle into a home object MyHomeInterface myHomeObject =(MyHomeInterface) javax.rmi.PortableRemoteObject.narrow(homeHandle.getHomeObject(), MyHomeInterface.class); // Resume using the home object myHomeObject.create();

Gestion des transactions


Michel Buffa (buffa@unice.fr), UNSA 2002

Gestion de transactions
Service cl pour le dveloppement ct serveur, Permet des applications de fonctionner de manire robuste, Les transactions sont trs utiles lorsqu'on effectue des oprations de persistance, comme des mises--jours dans une base de donnes Dans ce chapitre nous prsentons le concept de transaction et sa mise en application au sein des EJB.

Motivation pour les transactions


Oprations atomiques, bien que composes de plusieurs petites oprations
Ex : transfert de compte compte bancaire : on enlve sur un compte, on dpose sur l'autre Si une des deux oprations choue, perte de cohrence ! On veut que soit les deux oprations russissent, mais si une d'elles choue, on annule le tout et on remet les comptes dans l'tat initial ! On dit que les deux oprations forment une seule et mme transaction !

Traitement par exceptions


On peut s'en sortir en grant des exceptions
try { // retirer de l'argent du compte 1 } catch (Exception e){ // Si une erreur est apparue, on arrte. return; } try { // Sinon, on dpose l'argent sur le compte 2 } catch (Exception e){ // Si une erreur est apparue, o s'arrte, mais avant, on redpose //l'argent sur le compte 1 return; }

Qu'en pensez-vous ?

Traitement par exceptions


Et si on choue la dernire opration 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 oprations diffrentes ? Comment on teste tous les cas d'erreur ?

Panne rseau ou panne machine

Panne rseau ou panne machine


Le rseau plante, le client reoit une RMI Remote Exception L'erreur est intervenue avant qu'on enlve l'argent, ou aprs ?
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, il n'est pas suffisant !

Partage concurrent de donnes

Partage concurrent de donnes


Plusieurs clients consultent et modifient les mmes donnes On ne peut tolrer de perte d'intgrit des donnes !

Problmes rsolus par les transactions !


Un transaction est une srie d'oprations qui apparaissent sous la forme d'une large opration atomique. Soit la transaction russit, soit elle choue.
Traduire par "toutes les oprations qui la composent"

Les transactions s'accordent avec les pannes machines ou rseau, Rpondent au problmes du partage de donnes.

Un peu de vocabulaire
Objet ou composant transactionel
Un composant bancaire impliqu dans une transaction. Un EJB compte bancaire, un composant .NET, CORBA

Gestionnaire de transaction
Celui qui en coulisse gre l'tat de la transaction

Ressource
L'endroit o on lit et crit les donnes : un DB, une queue de messages, autre

Gestionnaire de ressource
Driver d'accs une BD, une queue de message Implmentent l'interface X/Open XA, standard de facto pour la gestion de transactions

Les proprit ACID


Atomicit
Nombreux acteurs : servlet, corba, rmi-iiop, ejbs, DB Tous votent pour indiquer si la transaction s'est bien passe

Consistance
Le systme demeure consistent aprs l'excution d'une transaction (comptes bancaires ok!)

Isolation
Empche les transactions concurrentes de voir des rsultats partiels. Chaque transaction est isole des autres. Implment par des protocoles de synchronisation bas-niveau sur les BDs

Durabilit
Garantit que les mises jour sur une BD peuvent survivre un crash (BD, machine, rseau) En gnral, on utilise un fichier de log qui permet de faire des undos pour revenir dans l'tat avant le crash.

Modles de transactions
Il existe deux modles
1.

Flat transactions ou transactions plat


Supportes par les EJBs

2.

Nested transactions ou transactions imbriques


Non supportes par les EJBs pour le moment

Flat transactions
Modle le plus simple. Aprs qu'une transaction ait dmarr, on effectue des oprations Si toutes les oprations sont ok, la transaction est commite (commited), sinon elle choue (aborted) En cas de commit, les oprations sont valides (permanent changes) En cas d'abort, les oprations sont annules (rolled back). L'application est galement prvenue

Flat transactions

Comment s'effectue le rollback ?


Tant qu'il n'y a pas de commit, les modifications une BD ne sont pas permanentes Dans un contexte de composants, tout est fait en coulisse. Vous n'avez pas vous proccuper de l'tat de votre bean Il sera restaur en cas de rollback.

Transactions imbriques
Cas d'cole : on veut faire un tour du monde
1. 2. 3. 4.

Notre application achte un billet de train de Nice Marseille, Puis un billet d'avion de Marseille Londres, Puis un billet d'avion de Londres New-York, L'application s'aperoit qu'il n'y a plus de billet d'avion disponible ce jour-l pour New-York

Tout choue et on annule toutes les rservations !

Transactions imbriques
Avec un modle de transactions imbrique, une transaction peut inclure une autre transaction, Si on ne trouve pas de vol pour New-York, on essaiera peut-tre de prendre une correspondance par Philadelphie

Transactions imbriques

Gestion des transactions avec les EJBs


Seul le modle flat est support. Le code que le dveloppeur crit, s'il dcide de grer les transactions par programmation, demeurera d'un trs haut niveau,
Simple vote pour un commit ou un abort, Le container fait tout le travail en coulisse

3 manires de grer les transactions


1. 2. 3.

Par programmation, De manire dclarative, De manire initie par le client.

Gestion des transactions par programmation


Responsable : le dveloppeur de bean Il dcide dans son code du begin, du commit et du abort Ex: le banquier

Gestion des transactions dclarative


Le bean est automatiquement enrl (enrolled) dans une transaction Le container fait le travail

Gestion des transactions dclarative


Gnial pour le dveloppeur !
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems,Inc.//DTD Enterprise JavaBeans 2.0//EN""http://java.sun.com/dtd/ejb-jar_2_0.dtd"> <ejb-jar> <enterprise-beans> <session> <ejb-name>Hello</ejb-name> <home>examples.HelloHome</home> <remote>examples.Hello</remote> <ejb-class>examples.HelloBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> // ou Bean... </session> </enterprise-beans> </ejb-jar>

Transactions inities par le client

Que choisir ?
Par programmation : contrle trs fin possible Dclaratif : super, mais granularit importante, Contrl par le client
N'empche pas de grer les transactions dans le bean (par programmation ou de manire dclarative) Ajoute une couche de scurisation en plus, qui permet de dtecter les crashes machine, rseau, etc

Transactions et entity beans


Dans une transaction, on accde un entity bean :
ejbLoad() est appel : chargement des donnes de la DB dans le bean, Un verrou (lock) est acquis sur la DB, assurant la consistance, Juste aprs l'appel du commit de la transaction, ejbStore() est appel, qui met jour la DB et libre le verrou. On a donc les appels ejbLoad(), aux mthodes mtiers et l'appel ejbStore() qui se trouvent dans la transaction.

Transactions et entity beans


Si on contrlait la transaction dans le bean
Dmarrer la transaction avant l'appel ejbLoad() ou au tout dbut de ejbLoad(), Faire le commit la fin de ejbStore() ou juste aprs l'appel ejbStore().

Problme : le client n'appelle jamais directement ejbLoad() ou ejbStore() !


Il passe par l'EJB object

Bean-Managed transactions illgales pour les entity beans. Seules les transactions gres par le container sont autorises !

Transactions et entity beans


Consquence : un entity bean n'accde pas la BD chaque appel de mthode, mais chaque transaction. Si un entity s'excute trop lentement, il se peut qu'une transaction intervient pour chaque appel de mthode, impliquant des accs BD. Solution : inclure plusieurs appels de mthodes de l'entity dans une mme transaction. Se fait en prcisant les attributs de transaction du bean.

Transactions et Message-Driven Beans


Bean-Managed Transactions
La transaction commence et se termine aprs que le message a t reu par le MDB. On indique dans le descripteur de dploiement les aknowledgement modes pour indiquer au container comment accuser rception

Container-Managed Transactions
La rception du message s'inscrit dans la mme transaction que les appels de mthodes mtier du MDB. En cas de problme, la transaction fait un rollback. Le container envoi accus de rception (message acknowledgement)

Pas de transaction
Le container accusera rception aprs rception. Quand exactement, ce n'est pas prcis

Transactions et Message-Driven Beans


Que choisir ? Si on dcide de ne pas laisser le container grer les transactions, on a pas de moyen de conserver le message dans la queue de destination si un problme arrive.
On choisit Container-Managed Transaction

Pige : si un MDB est expditeur et consommateur du message, le tout intervient dans une mme transaction
Impossible de terminer ! Le message expdi n'est pas mis dans la queue de destination de manire dfinitive tant que l'envoi n'est pas commit. Donc le message ne peut tre consomm! Cqfd. Solution : appeler commit() sur l'objet JMS session juste aprs l'envoi.

Attributs de transactions gres par le container


Pour chaque bean, on prcise des attributs de transaction
Obligatoire pour chaque bean, doit figurer dans le descripteur de dploiement, On peut spcifier des attributs pour le bean entier ou mthode par mthode, On peut prciser les deux Le plus restrictif gagne. Chaque mthode mtier doit tre traite (globalement ou individuellement) Pour les entity beans, il faut en plus couvrir les mthode de l'interface home, car elles impliquent des accs BD.

Exemple de dclaration d'attributs (1)


<assembly-descriptor> <!-- This demonstrates setting a transaction attribute on every method on the bean class. --> <container-transaction> <method> <ejb-name>Employee</ejb-name> <method-name>*</method-name> </method> <!-- Transaction attribute. Can be "NotSupported", "Supports", "Required", "RequiresNew", "Mandatory", or "Never". <trans-attribute>Required</trans-attribute> </container-transaction> <!-- You can also set transaction attributes on individual methods. --> <container-transaction> <method> <ejb-name>Employee</ejb-name> <method-name>setName</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> -->

Exemple de dclaration d'attributs (2)


<!-You can even set different transaction attributes on methods with the same name that take different parameters. --> <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>

Valeur des attributs de transaction


Required
Le bean est toujours dans une transaction. Si une transaction pour ce bean existe, alors le bean la rejoint (join), sinon, le container cre une nouvelle transaction.

La plupart du temps propos comme valeur par dfaut 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 crdit et bean commande, Lors d'un passage de commande, on envoie la commande, puis on dbite la carte de crdit, Si le bean session a comme attribut de transaction Required, une transaction est cre ds que le passage de commande dmarre, Lors de l'appel au bean Commande, si celui-ci est galement en mode Required, il rejoindra la transaction en cours. Idem lors de l'appel au bean Carte de Crdit, Si un problme se pose, la carte de crdit ne sera pas dbite et la commande ne sera pas passe.

Attribut de transaction : RequiresNew


RequiresNew
Le bean est toujours dans une nouvelle transaction. Si une transaction existe, elle est suspendue, Lorsque la nouvelle transaction se termine (abort ou commit), l'ancienne transaction est rsume.

Utile si on veut respecter les proprits ACID dans l'unit du bean, sans qu'une logique externe intervienne.

Attribut de transaction : Supports


Supports
Semblable Required sauf que si une transaction n'existe pas, elle n'est pas cre. Si l'excution du bean intervient dans une transaction existante, il la rejoint nanmoins.

A viter pour les applications mission-critical !


Dans ce cas, choisir Required.

Attribut de transaction : Mandatory


Mandatory
Une transaction doit exister lorsque le bean est excut. Si ce n'est pas le cas, javax.ejb.TransactionRequiredException est leve et renvoye au client. Si le client est local, c'est
javax.ejb.TransactionRequiredLocalException qui est leve

Attribut sr, qui oblige le client inscrire sa logique dans une transaction avant d'appeler le bean.

Attribut de transaction : NotSupported


NotSupported
Le Bean ne supporte pas les transactions, Si une transaction existe lors de l'appel du bean, la transaction est suspendue, le bean s'excute, puis la transaction est rsume.

Utiliser cet attribut lorsque les proprits ACID ne sont pas importantes
Exemple : un bean qui fait des statistiques toutes les dix minutes en parcourant une BD. On tolre que les donnes lues ne sont peut-tre pas jour

Gain en performance vident.

Attribut de transaction : Never


Never
Le Bean ne supporte pas les transactions, Une exception javax.rmi.RemoteException ou javax.ejb.EJBException est envoye au client si une transaction existe au moment de l'appel du bean.

A utiliser lors du dveloppement d'une logique non transactionnelle.

Rsum sur les attributs de transaction


Soit T1 une transaction initie par le client, T2 la nouvelle transaction initie par le bean appel.

Dbut et fin d'une transaction

Tous les attributs ne s'appliquent pas tous les beans

Transactions gres par programmatiion


Plus complexes manipuler, mais plus puissantes, Le dveloppeur doit utiliser Java Transaction API (JTA)

CORBA Object Transaction Service (OTS)


Dans une transaction de nombreux partis sont impliqus : le driver de DB, le bean, le container, Premier effort pour assurer les transactions dans un systme distribu : le service CORBA Object Transaction Service (OTS) OTS = ensemble d'interfaces pour le gestionnaire de transactions, le gestionnaire de ressources, etc Mortel utiliser !

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, elle couvre tous les aspects complexes d'OTS, JTA s'adresse au dveloppeur d'application (vous) et simplifie grandement la gestion de transactions en contexte distribu.

Java Transaction API (JTA)


JTA permet au programmeur de contrler la gestion de transaction dans une logique mtier. Il pourra faire les begin, commit, rollback, etc Il peut utiliser JTA dans des EJB mais aussi dans n'importe quelle application cliente. JTA se compose de deux interfaces distinctes.

JTA : deux interfaces


Une pour les gestionnaires de ressources X/Open XA (hors sujet pour nous) Une pour le programmeur dsirant contrler les transactions : javax.transaction.UserTransaction

L'interface javax.transaction.UserTransaction
public interface javax.transaction.UserTransaction { public void begin(); public void commit(); public int getStatus(); public void rollback(); public void setRollbackOnly(); public void setTransactionTimeout(int); }

L'interface javax.transaction.UserTransaction

Constantes de la classe
javax.transaction.Status Constantes renvoyes par getStatus()
public interface javax.transaction.Status { public static final int STATUS_ACTIVE; public static final int STATUS_NO_TRANSACTION; public static final int STATUS_MARKED_ROLLBACK; public static final int STATUS_PREPARING; public static final int STATUS_PREPARED; public static final int STATUS_COMMITTING; public static final int STATUS_COMMITTED; public static final int STATUS_ROLLING_BACK; public static final int STATUS_ROLLEDBACK; public static final int STATUS_UNKNOWN; }

Constantes de la classe
javax.transaction.Status

Comparaison entre les deux mthodes


Transaction dclarative
/** * Dpose de l'argent sur un compte. */ public void deposit(double amt) throws AccountException { System.out.println("deposit(" + amt + ") called."); balance += amt; }

Ne pas oublier de spcifier l'attribut de transaction dans le descripteur

Comparaison entre les deux mthodes


Transaction par programmation
public void deposit(double amt) throws AccountException { try { System.out.println("deposit(" + amt + ") called."); javax.transaction.UserTransaction userTran = ctx.getUserTransaction(); userTran.begin(); balance += amt; userTran.commit(); } catch (Exception e) { throw new AccountException("Deposit failed because of " + e.toString()); } }

Comparaison entre les deux mthodes


Transaction par programmation Ne pas oublier de mettre dans le descripteur
... <transaction-type>Container</transaction-type> ...

Conseil : dmarrer et terminer la transaction dans le mme mthode, sinon on obtient du code-spaghetti !

Transactions inities par le client


C'est la dernire des mthodes prsentes au dbut de ce chapitre Il est ncessaire d'obtenir une rfrence sur un objet UserTransaction, fourni par JTA
Via JNDI !

Faire attention ce que chaque transaction ne dure pas longtemps !!!


Pige classique !

Transactions inities par le client


try { /* 1: Set environment up. You must set the JNDI Initial Context factory, the Provider URL, and any login names or passwords necessary to access JNDI. See your application server product's documentation for details on their particular JNDI settings. */ java.util.Properties env = ... /* 2: Get the JNDI initial context */ Context ctx = new InitialContext(env); /* 3: Look up the JTA UserTransaction interface via JNDI. The container is required to make the JTA available at the location java:comp/UserTransaction. */ userTran = (javax.transaction.UserTransaction)ctx.lookup("java:comp/UserTransaction"); /* 4: Execute the transaction */ userTran.begin(); // perform business operations userTran.commit(); } catch (Exception e) { // deal with any exceptions, including ones // indicating an abort. }

Isolation de transaction
Le "I" de ACID ! L'isolation cote cher en termes de performances, Ncessit de pouvoir rgler le niveau d'isolation entre transactions concurrentes !

Isolation de transaction
Un exemple : deux instances A et B d'un mme composant accdent une mme donne X dans une BD. Chacune
1. 2. 3.

Lit la valeur de X, Ajoute 10 la valeur lue, crit la nouvelle valeur dans la BD

Si chaque instance effectue ces oprations de manire atomique, pas de problmes !

Isolation de transaction
Ceci n'est pas garanti selon le niveau d'isolation choisi. Par exemple, si on ne prend pas de prcaution
1. 2. 3. 4.

A lit X, dans la BD on a X=0, B lit X, dans la BD on a X=0, A ajoute 10 X et crit le rsultat dans la BD. Dans la BD on a X=10, B ajoute 10 sa copie de X et crit le rsultat dans la BD. Dans la BD on a X=10, ce qui est anormal ! On a perdu le traitement effectu par A !

Isolation de transaction
Solution : utiliser un verrou. Chaque composant
1. 2. 3.

Demande un verrou, Fait le travail prcdent sur X, Libre le verrou

Gestion de file d'attente exclusion mutuelle, etc Tout ceci peut-tre rgl avec les EJBs

Niveau d'isolation avec les EJB


Le niveau d'isolation limite la faon dont les transactions multiples et entrelaces interfrent les unes sur les autres dans une BD multi-utilisateur. 3 types de violations possibles
1. 2. 3.

Lecture brouille, Lecture ne pouvant tre rpte, Lecture fantme.

Niveau d'isolation avec les EJB


Lecture brouille
La transaction T1 modifie une ligne, la transaction T2 lit ensuite cette ligne, Puis T1 effectue une annulation (rollback), T2 a donc vu une ligne qui n'a jamais vraiment exist.

Lecture ne pouvant tre rpte


T1 extrait une ligne, T2 met jour cette ligne, T1 extrait nouveau la mme ligne, T1 a extrait deux fois la mme ligne et a vu deux valeurs diffrentes.

Niveau d'isolation avec les EJB


Lecture fantme
T1 lit quelques lignes satisfaisant certaines conditions de recherche, T2 insre plusieurs lignes satisfaisant ces mmes conditions de recherche, Si T1 rpte la lecture elle verra des lignes qui n'existaient pas auparavant. Ces lignes sont appeles des lignes fantmes.

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 rptes et les lignes fantmes, n'autorise pas les lectures brouilles Autorise les lignes fantmes mais pas les deux autres violations N'autorise aucune des trois violations

Repeatable

TRANSACTION_REPEATABLE_READ

Serialisable

TRANSACTION_SERIALIZABLE

Quel niveau utiliser


Uncommited
Uniquement si on est sr qu'une transaction ne pourra tre mise en concurrence avec une autre. Performant mais dangereux ! A viter pour les applications mission-critical !

Commited
Utile pour les applications qui produisent des rapports sur une base de donne. On veut lire des donnes consistances, mmes si pendant qu'on les lisait quelqu'un tait en train de les modifier. Lisent un snapshot des donnes commites Niveau d'isolation par dfaut de la plupart des BD (Oracle)

Quel niveau utiliser


Repeatable
Lorsqu'on veut pouvoir lire et modifier des lignes, les relire au cours d'une mme transaction, sans perte de consistance.

Serialisable
Pour les applications mission-critical qui ncessitent un niveau d'isolation absolu, ACID 100% ! Attention ,les performances se dgradent vitesse grand V avec ce mode !

Comment spcifier ces niveaux ?


Transactions gres par le bean
Appel de
java.sql.Connection.SetTransactionIsolation(...).

Transactions gres par le container


Non, on ne peut pas spcifier le niveau d'isolation dans le descripteur ! On le fera via le driver JDBC, ou via les outils de configuration de la DB ou du container, Problmes de portabilit !

Impossibilit de spcifier le niveau d'isolation ???

Deux stratgies
Lorsqu'on veut grer les transactions, on doit toujours choisir entre deux stratgies
1.

Stratgie pessimiste
Tout peut foirer, on prend donc un verrou lors des accs BD, on fait notre travail, puis on libre le verrou.

2.

Stratgie optimiste
Peu de chance que a foire, espre que tout va bien se passe. Nanmoins, si la BD dtecte une collision, on fait un rollback de la transaction.

Que faire dans le code EJB ???


Ok, nous avons vu comment spcifier le type de gestion de transaction, gre par le bean ou le container, Nous avons vu les niveaux d'isolations, que l'on spcifie la plupart du temps via les pilotes JDBC, Mais que faire en cas de rollback par exemple
On ne peut pas re-essayer indfiniment d'excuter une transaction, on peut envoyer une Exception au client On veut galement tre tenu au courant de ce qu'il se passe pendant l'excution d'une transaction.

Que faire dans le code EJB ???


En cas de rollback, si on envoie une Exception au client, que faire de l'tat du bean ?
Si le bean est stateful, on risque d'avoir un tat incorrect (celui qui a provoqu l'chec de la transaction), Lors du design d'un bean, il faut prvoir la possibilit de restaurer un tat correct, Le container ne peut le faire pour vous car le traitement est en gnral spcifique l'application, Il peut nanmoins vous aider raliser cette tche.

Que faire dans le code EJB ???


L'EJB peut implementer une interface optionnelle javax.ejb.SessionSynchronization

public interface javax.ejb.SessionSynchronization { public void afterBegin(); public void beforeCompletion(); public void afterCompletion(boolean); }

Uniquement pour les session beans stateful

Que faire dans le code EJB ???


Le container appelle afterCompletion() que la transaction se soit termine par un commit ou par un abort
Le paramtre de la mthode nous signale dans quel cas on se trouve
public class CountBean implements SessionBean, SessionSynchronization { public int val; public int oldVal; public void ejbCreate(int val) { this.val=val; this.oldVal=val; } public void afterBegin() { oldVal = val;} public void beforeCompletion() {} public void afterCompletion(boolean b) { if (b == false) val = oldVal; } public public public public public } int count() { return ++val; } void ejbRemove() {} void ejbActivate() {} void ejbPassivate() {} void setSessionContext(SessionContext ctx) {}

Relations avec beans BMP et CMP


Michel Buffa (buffa@unice.fr), UNSA 2002

On complique un peu l'tude des entity beans !


Les entity beans reprsentant des donns dans une BD, il est logique d'avoir envie de s'occuper de grer des relations Exemples
Une commande et des lignes de commande Une personne et une adresse Un cours et les lves qui suivent ce cours Un livre et ses auteurs

Nous allons voir comment spcifier ces relations dans notre modle EJB

Concepts abords
Cardinalit (1-1, 1-n, n-n), Direction des relations (bi-directionnelles, unidirectionnelles), Agrgation vs composition et destructions en cascade, Relations rcursives, circulaires, agressive-load, lazyload, Intgrit rfrentielle, Accder aux relations depuis un code client, via des Collections, Comment grer tout a en BMP et en CMP !

Diffrence entre BMP et CMP pour les relations


En BMP il faut tout faire la main
public class OrderBean implements EntityBean { // 1 - attributs // 2 - mthodes get/set // 3 - code pour la gestion des relations dans les // } mthodes ejbXXX

Diffrence entre BMP et CMP pour les relations


En CMP il faut tout faire dans le descripteur
<ejb-jar> <enterprise-beans> ... define enterprise beans ... </enterprise-beans> <relationships> ... define EJB relationships ... </relationships> </ejb-jar>

Le container gnre le code pour vous !

Cardinalit
La cardinalit indique combien d'instances vont intervenir de chaque ct d'une relation One-to-One (1:1)
Un employ a une adresse

One-to-Many (1:N)
Un PDG et ses employs

Many-to-Many (M:N)
Des tudiants suivent des cours

Cardinalit

Relations 1:1
Reprsente typiquement par une cl trangre dans une BD Ex : une commande et un colis

Relations 1:1 en BMP


public class OrderBean implements EntityBean { private String orderPK; private String orderName; private Shipment shipment; // EJB local object stub public Shipment getShipment() { return shipment; } public void setShipment(Shipment s) { this.shipment = s;} ... public void ejbLoad() { // 1: SQL SELECT Order. This also retrieves the shipment foreign key. // 2: JNDI lookup of ShipmentHome // 3: Call ShipmentHome.findByPrimaryKey(), passing in the shipment the foreign key } public void ejbStore() { // 1: Call shipment.getPrimaryKey() to retrieve the Shipment foreign key // 2: SQL UPDATE Order. } } This also stores the Shipment foreign key.

Relations 1:1 en CMP


public abstract class OrderBean implements EntityBean { // Pas d'attributs public abstract Shipment getShipment(); 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> ... </enterprise-beans> <relationships> <! Ceci dclare une relation --> <ejb-relation> <! Le nom donn cette relation --> <ejb-relation-name>Order-Shipment</ejb-relation-name> <! Ceci dclare la premire 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> -->

Relations 1:1 en CMP


<!-- Recall that a CMP entity bean has an abstract get/set method for the relationship. We need to tell the container which get/set method corresponds to

this relationship, so that the container can generate the appropriate scaffolding code when subclassing our bean. That is the purpose of this element, which is called the container-managed relationship (CMR) field. The value of the CMR field should be the name of your

get/set method, but without the get/set, and with a slight change in capitalization. --> <cmr-field><cmr-field-name>shipment</cmr-field-name></cmr-field> </ejb-relationship-role> <! Fin de la premire moiti de la relation !!!> getShipment() becomes shipment.

Relations 1:1 en CMP


<!-- 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>

Relations 1:N
Exemple : une entreprise a plusieurs employs

Relations 1:N
Exemple : une entreprise a plusieurs employs
Solution plus propre (viter les BLOBs!)

Relations 1:N avec BMP, exemple


public class CompanyBean implements EntityBean { private String companyPK; private String companyName; private Vector employees; // Vector d'EJB object stubs

public Collection getEmployees() { return employees; } public void setEmployees(Collection e) { this.employees = e;} ... public void ejbLoad() { // 1: SQL SELECT Company // 2: JNDI lookup de EmployeeHome // 3: Appel de EmployeeHome.findByCompany(companyPK), gnre un second ordre SQL } public void ejbStore() { // 2: SQL UPDATE Company }

Relations 1:N avec BMP


Le bean Employee a accs la cl trangre, pas le bean Company
C'est pourquoi ejbLoad() appelle un finder de la classe Employee, qui renvoie une collection de stubs vers les employs qui appartiennent la compagnie recherche On aurait pu en un seul ordre SQL rcuprer toutes les cls trangres des employs, mais il aurait fallu encore refaire une srie de requtes SQL pour obtenir les rfrences vers les objets distants

Relations 1:N avec CMP, exemple (1)


public abstract class CompanyBean implements EntityBean { // pas d'attributs

public abstract Collection getEmployees(); public abstract void setEmployees(Collection employees);

...

public void ejbLoad() {} public void ejbStore() {} }

// Empty // Empty

Relations 1:N avec CMP, exemple (2)


<ejb-jar> <enterprise-beans> ... </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>

Relations 1:N avec CMP, exemple (3)


<!-- When you have a relationship with more than one object, you can either use a java.util.Collection or a java.util.Set. We need to identify which one we're using. How do you choose between a Collection and a Set? A Collection can contain duplicates, whereas a Set cannot. bean's get/set methods. --> <cmr-field> <cmr-field-name>lineItems</cmr-field-name> <cmr-field-type>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, remarques


Les relations 1:N sont souvent bien plus performantes en CMP qu'en BMP En BMP deux tapes sont ncessaires
1. 2.

ejbLoad() pour la partie "1" de la relation, Appel une mthode finder pour la partie "N" de la relation. Granularit l'chelle du bean Il peut en une seule requte charger les deux parties de la relation.

En CMP, si le container est bon,

Relations M:N
Un tudiant suit plusieurs cours, un cours a plusieurs tudiants inscrits
Table de jointure ncessaire.

Relations M:N, choix de conception


Deux possibilits lorsqu'on modlise cette relation avec des EJBs
1.

2.

Utiliser un troisime EJB pour modliser la table de jointure. On veut peut-tre mmoriser la date o un tudiant s'est inscrit, etc Cet EJB possdera deux relations 1:N vers le bean Student et le vers le bean Course Si on a rien besoin de plus part la relation, on peut utiliser simplement deux EJB, chacun ayant un attribut correspondant une Collection de l'autre EJB

Relations M:N, avec un troisime EJB, exemple en BMP (1)


En BMP
public class StudentBean implements EntityBean { private String studentPK; private String studentName; ... public void ejbLoad() } public class CourseBean implements EntityBean { private String coursePK; private String courseName; ... public void ejbLoad() } { // SQL SELECT Course } public void ejbStore() { // SQL UPDATE Course } { // SQL SELECT Student } public void ejbStore() { // SQL UPDATE Student }

Relations M:N, avec un troisime EJB, exemple en BMP (2)


public class EnrollmentBean implements EntityBean { private String enrollmentPK; private Student student; private Course course; // EJB local object stub // EJB local object stub

public Course getCourse() { return course; } public void setCourse(Course c) { this.course = c;} public Student getStudent() { return student; } public void setStudent(Student s) { this.student = s; } ... public void ejbLoad() { // 1: SQL SELECT Enrollment. // and Course. This loads both the Enrollment plus the foreign keys to Student

// 2: JNDI lookup of StudentHome, CourseHome // 3: Call findByPrimaryKey() on both the Student and Course homes, passing the foreign keys } public void ejbStore() { // 1: Call getPrimaryKey() on Student,Course. // 2: SQL UPDATE Enrollment } } This gives us our foreign keys.

Relations M:N, avec un troisime EJB, 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, avec un troisime EJB, exemple en CMP (2)


public abstract class EnrollmentBean implements EntityBean { // Pas d'attributs public abstract Course getCourse(); public abstract void setCourse(Course c);

public abstract Student getStudent(); public abstract void setStudent(Student s);

...

public void ejbLoad() {} public void ejbStore() {} }

// Vide // Vide

Relations M:N, avec un troisime EJB, exemple en CMP (3)


<ejb-jar> <enterprise-beans> ... </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, avec un troisime EJB, 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>

Relations M:N, avec un troisime EJB, 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, exemple (1)


public class StudentBean implements EntityBean { private String studentPK; private String name; private Vector courses; // EJB object stubs

public Collection getCourses() { return courses; } public void setCourses(Collection c) { this.courses = c;} ... public void ejbLoad() { // 1: SQL SELECT Student // 2: JNDI lookup of CourseHome // 3: Call CourseHome.findByStudent(studentPK) } public void ejbStore() { // SQL UPDATE Student }

Vraie relation M:N avec BMP, exemple (2)


public class Course implements EntityBean { private String coursePK; private String name; private Vector students; // EJB object stubs

public Collection getStudents() { return students; } public void setStudents(Collection s) { this.students = s;} ... public void ejbLoad() { // 1: SQL SELECT Course // 2: JNDI lookup of StudentHome // 3: Call StudentHome.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(); public abstract void setCourses(Collection courses); ... public void ejbLoad() {} public void ejbStore() {} } public abstract class CourseBean implements EntityBean { // Pas d'attributs public abstract Collection getStudents(); public abstract void setStudents(Collection students); ... public void ejbLoad() {} public void ejbStore() {} } // Vide // Vide // Empty // Empty

Vraie relation M:N avec CMP, exemple (2)


<ejb-jar> <enterprise-beans> ... </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.util.Collection</cmr-field-type> </cmr-field> </ejb-relationship-role> ...

Vraie relation M:N avec CMP, 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.util.Collection</cmr-field-type> </cmr-field> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar>

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

Implmenter une relation bidirectionnelle en BMP, exemple


public class OrderBean implements EntityBean { private String orderPK; private String orderName; // EJB local object stub, must be stored/loaded private Shipment shipment; public Shipment getShipment() { return shipment; } public void setShipment(Shipment s) { this.shipment = s; } ... } public class ShipmentBean implements EntityBean { private String shipmentPK; private String shipmentName; // EJB local object stub, must be stored/loaded private Order order; public Order getOrder() { return order; } public void setOrder(Order o) { this.order = o; } ... }

Implmenter une relation unidirectionnelle en BMP, exemple


public class OrderBean implements EntityBean { private String orderPK; private String orderName; // EJB local object stub, must be stored/loaded private Shipment shipment; public Shipment getShipment() { return shipment; } public void setShipment(Shipment s) { this.shipment = s; } ... } public class ShipmentBean implements EntityBean { private String shipmentPK; private String shipmentName; // No Order stub, no Order get/set method ... }

Implmenter une relation bidirectionnelle en CMP, exemple (1)


public abstract class OrderBean implements EntityBean { // no fields public abstract Shipment getShipment(); public abstract void setShipment(Shipment s); ... public void ejbLoad() {} public void ejbStore() {} } public abstract class ShipmentBean implements EntityBean { // no fields public abstract Order getOrder(); public abstract void setOrder(Order o); ... public void ejbLoad() {} public void ejbStore() {} } // Empty // Empty // Empty // Empty

Implmenter une relation bidirectionnelle en CMP, exemple (2)


<ejb-jar> <enterprise-beans> ... </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>

Implmenter 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 modle de donnes dans la DB


La directionalit peut ne pas correspondre celle du modle de donnes dans la DB
Schma normalis

Schma dnormalis

Relations et interfaces locales


On ne le rptera jamais assez, les entity beans sont prvus pour tre accds via leurs interfaces locales
Pour des raisons de performance videntes, On peut nanmoins faire des tests unitaires depuis un client remote mais !

Si un client fait un accs remote via un getXXX() un champs correspondant une relation
Il reoit une Collection. Sans doute pas la mme que celle utilis par le container. Ncessit de faire un cast CORBA/II-OP, trs cher (instruction narrow)

Choisir la directionalit ?
Premier critre : la logique de votre application, Second critre : si le schma relationnel existe, s'adapter au mieux pour viter de mauvaises performances.

Lazy-loading des relations


Agressive-loading
Lorsqu'on charge un bean, on charge aussi tous les beans avec lesquels il a une relation. Cas de la Commande et des Colis plus tt dans ce chapitre. Dans le ejbLoad() on appelle des finders Peut provoquer un norme processus de chargement si le graphe de relations est grand.

Lazy-loading
On ne charge les beans en relation que lorsqu'on essaie d'accder l'attribut qui illustre la relation. Tant qu'on ne demande pas quels cours il suit, le bean Etudiant n'appelle pas de mthode finder sur le bean Cours.

Lazy-loading des relations avec BMP


public class OrderBean implements EntityBean { private String orderPK; private String orderName; private String shipmentFK; // Foreign key to shipment private Shipment shipment; // EJB local object stub public void ejbLoad() { // 1: SQL SELECT Order, loading the shipment foreign key // 2: Set shipmentFK field to the loaded key } public Shipment getShipment() { // 1: JNDI lookup of ShipmentHome // 2: Call ShipmentHome.findByPrimaryKey(shipmentFK) return shipment; } ... }

Lazy-loading des relations avec CMP


Pas besoin de s'en occuper, le container fait le travail en coulisse. Se configure dans le descripteur propritaire, Tous les containers ne supportent pas le lazyloading
Nombreuses options chez l'un ou chez l'autre vendeur. lment-cl dans le choix d'un container.

Agrgation vs Composition et destructions en cascade


Relation par Agrgation
Le bean utilise un autre bean Consquence : si le bean A utilise le bean B, lorsqu'on dtruit A on ne dtruit pas B. Par exemple, lorsqu'on supprime un tudiant on ne supprime pas les cours qu'il suit. Et vice-versa.

Relation par Composition


Le bean se compose d'un autre bean. Par exemple, une commande se compose de lignes de commande Si on dtruit la commande on dtruit aussi les lignes correspondantes. Ce type de relation implique des destructions en cascade..

Destructions en cascade avec BMP


public class OrderBean implements EntityBean { private String orderPK; private String orderName; private Shipment shipment; // EJB local object stub

public Shipment getShipment() { return shipment; } public void setShipment(Shipment s) { this.shipment = s;}

...

public void ejbRemove() { // 1: SQL DELETE Order // 2: shipment.remove(); } }

Destructions en cascade avec CMP


<ejb-jar> <enterprise-beans> ... </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 dfinit une relation en CMP, on peut aussi indiquer la requte qui permet de remplir le champs associ la relation. On fait ceci l'aide d'EJB-QL SELECT o.customer FROM Order o
Renvoie tous les clients qui ont plac une commande

Principale diffrence avec SQL, l'oprateur "."


Pas besoin de connatre le nom des tables, ni le nom des colonnes

Relations et EJB-QL
On peut aller plus loin
SELECT o.customer.address.homePhoneNumber FROM Order o

On se promne le long des relations

Relations rcursives
Relation vers un bean de la mme classe
Exemple : Employ/Manager

Rien de particulier, ces relations sont implmentes exactement comme les relations non rcursives

Relations circulaires
Similaire au relations rcursives sauf qu'elles impliquent plusieurs types de beans
Ex : un employ travaille dans une division, une division possde plusieurs ordinateurs (workstation), une workstation est alloue un employ

Ce type de relation, en cas de agressive-loading peut mener une boucle sans fin
Mme problme avec les destructions en cascade

Relations circulaires
Plusieurs stratgies sont possibles
1.

2. 3. 4. 5.

Certains containers proposent d'optimiser le chargement d'un bean en chargeant toutes ses relations en cascade dans le ejbLoad(). Attention si relations circulaires ! Supprimer une des relations (!!!) si le modle de conception le permet. Supprimer la bidirectionnalit d'une des relations pour briser le cercle, si le modle de conception le permet. Utiliser le lazy-loading et ne pas faire de destruction en cascade. Les meilleurs moteurs CMP dtectent les relations circulaires et vous permettent de traiter le problme avant le runtime.

Intgrit rfrentielle
Un bean Compagnie, Division, etc a des relations avec un bean Employ
Si on supprime un employ, il faut vrifier qu'il est bien supprim partout o on a une relation avec lui.

Problme classique dans les SGBDs


Rsolus l'aide de triggers. Ils se dclenchent sitt qu'une perte d'intgrit risque d'arriver et effectuent les oprations ncessaires. On peut aussi utiliser des procdures stockes via JDBC. Ces procdures effectuent la vrification d'intgrit.

Intgrit rfrentielle
Grer l'intgrit dans le SGBD est intressant si la BD est attaque par d'autres applications que les EJBs Autre approche : grer l'intgrit dans les EJBs
Solution plus propre, Le SGBD n'est plus aussi sollicit, Avec BMP il faudra grer le tout la main Avec CMP, le container fait le travail tout seul !

Intgrit rfrentielle
Et dans un contexte distribu ? Plusieurs serveurs d'application avec le mme composant peuvent accder des donnes sur le mme SGBD, Comment mettre jour les relations ? Problme rsolu par les transactions !!!

Relations, intgrit rfrentielle et code client


Ok, les relations "1:N" impliquent les Collections, mais comment un client peut-il changer une des relations parmi les "N" ?

Relations, intgrit rfrentielle et code client, exemple (1)


public abstract class CompanyBean implements EntityBean { // pas d'attributs

public abstract Collection getEmployees(); public abstract void setEmployees(Collection employees);

...

public void ejbLoad() {} public void ejbStore() {} }

// vide // vide

Relations, intgrit rfrentielle et code client, exemple (1)


// Lookup local home objects Context ctx = new InitialContext(...); CompanyHome companyHome = (CompanyHome) PortableRemoteObject.narrow( ctx.lookup("CompanyHome"), CompanyHome.class); EmployeeHome employeeHome = (Employee) PortableRemoteObject.narrow( ctx.lookup("EmployeeHome"), EmployeeHome.class); // Make a new employee Employee employeeA = employeeHome.create("Ed Roman"); // Find a company Company company = companyHome .findByPrimaryKey("The Middleware Company"); Collection employees = company.getEmployees(); // Add the employee to the company.This demonstrates the add() Collection API method employees.add(employeeA);

Relations, intgrit rfrentielle et code client, exemple (2)


// Look at each employee in the company. // This demonstrates using iterators to loop through collections Iterator i = employees.iterator(); while (i.hasNext()) { Employee emp = (Employee) i.next(); System.out.println(emp.getName()); }

// Remove the employee from the company. // This demonstrates the remove() Collection API employees.remove(employeeA);

Relations, intgrit rfrentielle et code client, remarques


On manipule la mme collection dans le bean client et le bean serveur car on accde un objet local Attention si appels remote, la Collection implmente parle container n'est pas celle du JDK standard !
Elle prserve l'intgrit :

Relations, intgrit rfrentielle et code client, remarques


Attention avec les iterators et les relations
Si vous voulez supprimer une relation dans un iterator, utiliser uniquement : java.util.Iterator.remove() Sinon a casse l'itrateur !

Rsum

Bonnes pratiques de persistance


Michel Buffa (buffa@unice.fr), UNSA 2002

On manipule des donnes persistantes


Application moderne = manipuler des donnes, les lire, les crire, les modifier. Le plus souvent, ces donnes sont dans un SGBD. Lorsqu'on dveloppe une application base sur les EJB, la gestion de la persistance peut tre aussi simple que mapper un EJB sur une table, Mais aussi devenir effroyablement complexe !

Dans ce chapitre
Quand utiliser des entity beans, Choisir entre BMP et CMP, Quelques design patterns

Quand utilise des entity beans


Utiliser simplement des sessions beans + JDBC ? Pourquoi pas ?
Contrle total via JDBC, Approche .NET

Utiliser des entity beans BMP ou CMP


Le container fait une partie du travail (BMP) ou la totalit (CMP), Il appelle ejbLoad(), ejbStore() dans votre dos Perte de contrle parfois droutante : duquer les dveloppeurs !

Analogie avec le passage de paramtres


Lorsqu'on appelle un session bean, les rsultats sont passs par valeur, Lorsqu'on appelle un entity bean, on rcupre des stubs sur les objets rsultats.
Similaire un passage par rfrence.

La plupart des temps les session beans sont clients des entity beans, et y accdent via leur interface locale. Les clients des sessions peuvent tre des servlets ou une application classique.

Analogie avec le passage de paramtres


Rflchissez Est-ce plus avantageux pour un client normal de recevoir des rsultats distants par rfrence
NON ! Il vaut mieux les recevoir par valeur, srialiss.

Est-ce plus avantageux pour un session bean de recevoir des rsultats par rfrence ?
OUI, il tourne dans le mme container que le bean serveur !

CONCLUSION : utiliser des sessions beans comme front-end pour les clients finaux !
Srialisent les rsultats finaux vers le client.

Cache
Les sessions beans ne reprsentent pas des donnes, et ne peuvent donc pas tre caches, Les donnes manipules ne durent que le temps de la session. D'un autre ct, les entity beans peuvent tre cachs travers plusieurs transactions
Dans le descripteur de dploiement spcifique Par exemple, on cachera les 1000 livres les plus demands chez Amazon.com !

Cache
Mais inutile de cacher des donnes peu partages
Donnes personnelles

Il est trs intressant d'utiliser des entity beans car souvent les donnes sont partages et sont plus souvent lues que modifies.

Un bon schma relationnel


Parfois changer deux colonnes dans une table peut prendre deux mois pour trois dveloppeurs !
Vridique ! A cause de code SQL incomprhensible 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
Rduction du code crire, normes descripteurs, mais le plus souvent ils sont gnrs par des wizards, RAD, Super pour prototyper, si on veut on peut toujours passer en BMP par la suite

Performances : CMP
Bien rgls, les beans CMP sont bien plus performants que les BMP, Le container peut rsoudre les relations en un seul, gros ordre SQL, On peut nanmoins optimiser les BMP avec la pattern Fat Key

Choix entre BMP et CMP


Debugging : CMP
Parfois, les bugs dans les CMPs sont durs trouver car tout se passe en coulisse Un descripteur mal spcifi Avec CMP on contrle tout

Contrle : BMP
Avec BMP on contrle tout, Mais les meilleurs containers ont des moteurs CMP trs puissants et paramtrables

Portabilit : CMP
Indpendant de la base de donnes.

Choix entre BMP et CMP


Gestion des relations : CMP
Depuis EJB 2.0, nombreuses amliorations. Gestion automatique de l'intgrit, langage EJB-QL, etc Containers trs performants aujourd'hui. Avec BMP : beaucoup de code crire, projet plus long dvelopper, l'argent rentre moins vite !!!

Courbe d'apprentissage : BMP mais le plus souvent par simple peur de ne pas se lancer dans CMP

Choix de la granularit
Doit-on faire de gros ou de petits composants? Depuis EJB 2.0 et les interfaces locales, il n'est plus ncessaires de concentrer les traitements pour minimiser les changes entre beans.
On peut faire de "petits" beans !

Exemple : commande contient des lignes de commandes.


On n'hsite plus, chaque ligne est un entity bean ! Auparavant, on pouvait utiliser des classes normales srialisables Mais on perd tout l'avantage des relations en EJB 2.0 !

Trucs et astuces sur la persistance


Parfois, pour des traitements ncessitant l'examen d'un grand nombre de donnes, il est prfrable d'utiliser des procdures stockes.
Exemple : trouver les comptes bancaires dbiteurs

viter de partager une source de donnes entre une application base d'EJB et une application externe.
Sinon, l encore, les procdures stockes peuvent centraliser une partie de la logique

Trucs et astuces sur la persistance


Attention, il y a aussi de nombreuses raisons pour NE PAS utiliser des procdures stockes
Tout repose sur le SGBD, goulot d'tranglement Peu portable, Mauvaise flexibilit, migration difficile, Maintenance ?

Trucs et astuces sur la persistance


Si on peut, adapter le modle de donnes au modle EJB.
vident si la source de donnes n'existe pas au dbut du projet.

N'oubliez pas que les donnes sont les donnes, les objets sont les donnes + le comportement !

Vous aimerez peut-être aussi