Académique Documents
Professionnel Documents
Culture Documents
02 Ejb
02 Ejb
Introduction gnrale
Michel Buffa (buffa@unice.fr), UNSA 2002
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 ?
Serveurs d'application
Development Tools
Presentation
HTML
Business Logic
Distributed Objects Transactions
Data Access
HTML Java
Content Management
Data
Java Application
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.
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
Architectures de composants
Adopt par l'industrie. "Train once, code anywhere" Portable facilement Rapid Application Development (RAD)
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)
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
J2EE
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
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 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
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
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
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
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)
EJ Bean EJ Bean
Code gnr
Comme pour les EJB Objects, le dveloppeur du bean doit spcifier une interface Home
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 !
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
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
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
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.
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; }
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; }
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.
/* * These are security methods - see Chapter X */ public boolean isCallerInRole(java.lang.String); public java.security.Principal getCallerPrincipal(); }
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>
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.
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
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 : 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,
Exemples
Saisie d'une commande, Compression vido, Gestion d'un caddy, d'un catalogue de produits, Transactions bancaires
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.
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
Consquence : une instance de Stateful Session Bean par client. Avec certains containers, les Stateful Session Beans peuvent tre persistants (BAS/BES) par srialisation.
Une instance de Stateless Session Bean n'est pas propre un client donn, elle peut tre partage entre chaque appel de mthode.
Rappelez-vous que javax.ejb.EnterpriseBean implmente java.io.Serializable Tous les attributs du Bean non transcients sont donc concerns.
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)
Ces deux mthodes permettent de rcuprer une rfrence sur l'EJBObject associ au Bean, remplace le this pour les EJB !
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 }
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()
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
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
public interface javax.ejb.EntityContext extends javax.ejb.EJBContext { public javax.ejb.EJBLocalObject getEJBLocalObject(); public javax.ejb.EJBObject getEJBObject(); public java.lang.Object getPrimaryKey(); }
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(); }
Ces mthodes ne sont ncessaires avec les Entity Beans CMP (Container Managed Persistence)
/** 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() { ... }
findindAllProducts() renvoie une Collection de cls primaires au container, Le container la transforme en Collection d'EJB Objects
/** 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.*/
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.
/* 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 : 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(); } } }
<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
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
Les attributs sont dclars dans la sous-classe gnre par le container ! Mais alors, comment y accde-t-on ? O les dclare-t-on ?
CMP
// CMP Subclass public class AccountBeanSubClass extends AccountBean { public String accountID; public String ownerName; public double balance; ...methods... } // PK
// abstract get/set methods public abstract float getSubTotal(); public abstract float getTaxes();
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 : 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
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 !
// 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."); } ...
* 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 : 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
<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>
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..
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.
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
Domaines possibles
Publish/Subscribe (pub/sub) : n producteurs, n consommateurs (tv) Point To Point (PTP) : n producteurs, 1 consommateur
2.
3.
4.
5.
6.
// 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); } }
La classe d'implmentation doit fournir une mthode ejbCreate() qui renvoit void et qui n'a pas d'arguments.
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.
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
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.
Piges !
Messages empoisonns (poison messages)
A cause des transactions un message peut ne jamais tre consomm
MDB empoisonn !
package examples;
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"
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.
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.
2.
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
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
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
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.
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>
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.
Qu'en pensez-vous ?
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 !
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
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.
2.
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
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
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
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
Bean-Managed transactions illgales pour les entity beans. Seules les transactions gres par le container sont autorises !
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
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.
La plupart du temps propos comme valeur par dfaut par les IDEs et leurs Wizards/diteurs de descripteurs
Utile si on veut respecter les proprits ACID dans l'unit du bean, sans qu'une logique externe intervienne.
Attribut sr, qui oblige le client inscrire sa logique dans une transaction avant d'appeler le bean.
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
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
Conseil : dmarrer et terminer la transaction dans le mme mthode, sinon on obtient du code-spaghetti !
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.
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.
Gestion de file d'attente exclusion mutuelle, etc Tout ceci peut-tre rgl avec les EJBs
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
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)
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 !
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.
public interface javax.ejb.SessionSynchronization { public void afterBegin(); public void beforeCompletion(); public void afterCompletion(boolean); }
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 !
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
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.
</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!)
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 }
...
// Empty // Empty
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.
Relations M:N
Un tudiant suit plusieurs cours, un cours a plusieurs tudiants inscrits
Table de jointure ncessaire.
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
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.
public abstract class CourseBean implements EntityBean { // Pas d'attributs public void ejbLoad() {} public void ejbStore() {} } // Vide // Vide
...
// Vide // Vide
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 }
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 }
Bidirectionnelle
On peut aller du bean A vers le bean B et inversement
</ejb-jar>
Schma dnormalis
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
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.
public Shipment getShipment() { return shipment; } public void setShipment(Shipment s) { this.shipment = s;}
...
<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
Relations et EJB-QL
On peut aller plus loin
SELECT o.customer.address.homePhoneNumber FROM Order o
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.
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 !!!
...
// vide // vide
// Remove the employee from the company. // This demonstrates the remove() Collection API employees.remove(employeeA);
Rsum
Dans ce chapitre
Quand utiliser des entity beans, Choisir entre BMP et CMP, Quelques design patterns
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.
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.
Utiliser une couche objet (entity beans) permet d'abstraire SQL et donc de faciliter la maintenance Pas facile faire avec des sessions beans
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
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.
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 !
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
N'oubliez pas que les donnes sont les donnes, les objets sont les donnes + le comportement !