Enterprise Javabeans 3.0: Introduction Générale
Enterprise Javabeans 3.0: Introduction Générale
Enterprise Javabeans 3.0: Introduction Générale
0
Introduction générale
Enterprise JavaBeans
Standard industriel pour un modèle de composant logiciel
distribué,
Permet d'implémenter des "objets métier" d'une manière
propre et réutilisable,
Pour le développement RAD d'applications côté serveur
Questions :
De quoi a-t-on besoin lorsqu'on développe une application
distribuée orientée objet ?
Qu'est-ce que les EJBs et qu'apportent-elles ?
Quels sont les acteurs dans l'écosystème EJB ?
Motivation des EJBs
Development Tools
Distributed
HTML Objects Data Access
HTML
Objects
Transactions
Enterprise Data
Java
Content Connectors
Data
Management
Java
Application Enterprise Deployment Services
Scalability Reliability Security Manageability
Encore mieux !
Autre possibilités
Composants Microsoft .NET
Ruby on rails, Python turbo gears, frameworks java
plus légers comme WebWork, Spring, etc.
EJB pour développer des composants
business
2 - L'assembleur d'application
Il s'agit de l'architecte de l'application
Il est client des EJBs achetées ou développées
Il décide de la combinaison de composants dont il a besoin
Fournit un GUI à l'application
Conçoit et développe de nouveau composants
Conçoit et développe les programmes clients
Définit le mapping avec les données manipulées par les
différents composants
En général, c'est un expert en Génie Logiciel, en UML et en
développement Java.
Il peut s'agir d'un intégrateur de systèmes, d'un consultant,
d'une équipe de développeurs/concepteurs maison…
L'écosystème EJB
3 - Le déployeur d'EJBs
Après que l'application ait été assemblée, elle doit être
déployée sur un ou plusieurs serveurs d'application
Attention à la sécurité (firewall, etc…)
Branchement de services annexes (LDAP, Lotus Notes,
Microsoft Active Directory, etc…) sur le serveur d'applications.
Choix du hardware, des SGBD, etc…
Paramétrage 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'hébergement de serveurs d'applications.
Exemples aux USA : www.hostJ2EE.com ou
www.loudcloud.com
L'écosystème EJB
4 - L'administrateur système
Vérifie 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, arrêt) du système.
Certains serveurs d'application savent téléphoner et
appeler l'administrateur système en cas de
problème.
Ponts avec les outils de Tivoli, Computer
Associates, … via JMX.
L'écosystème EJB
J2EE for the Real World
JDBC 2.0
Servlets/JSP EJB
Distributed
HTML Data Cache
Visual Servlets Triggers Data Access
Objects
On Demand Content
Enterprise Data
Java Management
Connectors Data
JDBC 2.0
Servlets/JSP EJB
Distributed
HTML Data Cache
Visual Servlets Triggers Data Access
Objects
On Demand Content
Enterprise Data
Java Management
Connectors Data
Session Beans
Modèlisent un traitement (business process)
Correspondent à des verbes, à des actions
Ex : gestion de compte bancaire, affichage de
catalogue de produit, vérifieur de données
bancaires, gestionnaire de prix…
Les actions impliquent des calculs, des accès à une
base de données, consulter un service externe
(appel téléphonique, etc.)
Entity beans
Modèlisent des données
Correspondent à des noms
Ce sont des objets java qui cachent des données d'une base
de données
Ce sont des objets persistants
Ex : un Bean Personne, un Bean compte bancaire, un Bean
produit, un Bean commande.
Serveurs pour des Beans Session le plus souvent
Servent de proxy entre la logique métier et les base de
données
Mapping base de donnée relationnelle/Objet facilité par EJB
2.0
Exemple de Session/Entity bean
Message-Driven Beans
Introduits à pârtir de la norme EJB 2.0, nous
sommes aujourd’hui en 3.0
Similaire aux Session bean : représentent des
verbes ou des actions,
On les invoque en leur envoyant des messages,
Ex : message pour déclencher des transactions
boursières, des autorisations d'achat par CB,
Souvent clients d'autres beans…
3 types de Beans : pourquoi ?
Difficile à écrire,
Difficile à maintenir,
Votre code est dépendant des API du vendeur
de middleware que vous utilisez.
Middleware implicite
Les EJB : middleware implicite mais API pour
descendre au bas niveau, Explicite
EJ
EJBean
Bean • Code simple
EJB Server
• Génération du code à
partir du Bean
Container EJB Container
EJB • Le code généré fournit
Transactions, Securité,
Persistance, Accès EJ
EJBean
Bean
Distant, gestion des
ressources, etc.
Serveur
• Fournit les services au
EJB
container
EJB Object : génération du code
• Utilisation du descripteur
de déploiement (fourni
par l'auteur du Bean)
Container • Paramètres de
EJB déploiement = securité,
EJ
EJBean
Bean mappings objets/BD
relationelle, etc.)
EJ
EJBean
Bean
Code généré
Constitution d'un EJB : l'interface distante
Javax.ejb.EJBObject dérive de
java.rmi.Remote,
Quiconque implémente Remote est appelable
à distance depuis une autre JVM,
EJB Objects = RMI-IIOP + EJB compatibles
RMI-IIOP = convention de passage de
paramètres + valeurs de retour lors d'appels de
méthode distante, entre autres…
Constitution d'un EJB : Home Object
Exemples
Saisie d'une commande,
Compression vidéo,
Gestion d'un caddy, d'un catalogue de produits,
Transactions bancaires…
Durée de vie d'un Session Bean
Défauts nombreux…
Gestion des versions, maintenance…
Pas de requêtes complexes…
Ex : on sérialize mille comptes bancaires. Comment
retrouver ceux qui ont un solde négatif ?
Pas si simple…
Détermination 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
La persistance à l'aide d'une BD Objet
Exemples
Compte bancaire (No, solde),
Employé, service, entreprises, livre, produit,
Cours, élève, examen, note,
•Dans getBalance() on
utilise plus de find,
•On utilise les
Exceptions
Caractéristiques des entity beans
Requêtes SQL:
Requêtes nommées:
Message-Driven Beans
Michel Buffa (buffa@unice.fr), UNSA 2002
Message-Driven Beans
Performance
Un client RMI-IIOP attend pendant que le serveur
effectue le traitement d'une requête,
Fiabilité
Lorsqu'un client RMI-IIOP parle avec un serveur, ce
dernier doit être en train de fonctionner. S'il crashe,
ou si le réseau crashe, le client est coincé.
Pas de broadcasting !
RMI-IIOP limite les liaisons 1 client vers 1 serveur
Messaging
Domaines possibles
Publish/Subscribe (pub/sub) : n
producteurs, n consommateurs
(tv)
Point To Point (PTP) : n
producteurs, 1 consommateur
JMS : les étapes
JMS : exemple de code (2)
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)
Transactions et MBD,
La production et la consommation du message sont dans
deux transactions séparées…
Sécurité,
Les MDB ne reçoivent pas les informations de sécurité du
producteur avec le message. On ne peut pas effectuer les
opérations classiques de sécurité sur les EJB.
Load-Balancing,
Modèle idéal : 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 avancés
package examples;
import javax.ejb.*;
import javax.jms.*;
public class PoisonBean
implements MessageDrivenBean, MessageListener {
...
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 gérées par le bean, non par
le container,
Certains serveurs peuvent configurer une "poison
message queue" ou posséder un paramètre "nb
max retries"
…
Comment renvoyer des résultats à
l'expéditeur du message ?
<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 références 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…)
La localisation java:comp/env/jdbc/ejbPool
Les informations réelles 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>
</session>
</enterprise-beans>
Resources factories (JDBC, JMS…)
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)
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)
<!--
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 déclarative
<!-- 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 déclaration 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 don’t need. -->
<exclude-list>
<description>
We don ’t have a 401k plan,so we don’t 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 déclarative
Qu'en pensez-vous ?
Traitement par exceptions
Gestionnaire de transaction
Celui qui en coulisse gère l'état de la transaction
Ressource
L'endroit où on lit et écrit les données : un DB, une queue de
messages, autre…
Gestionnaire de ressource
Driver d'accès à une BD, à une queue de message…
Implémentent l'interface X/Open XA, standard de facto pour la
gestion de transactions…
Les propriété ACID
Atomicité
Nombreux acteurs : servlet, corba, rmi-iiop, ejbs, DB… Tous votent pour
indiquer si la transaction s'est bien passée…
Consistance
Le système demeure consistent après l'exécution d'une transaction (comptes
bancaires ok!)
Isolation
Empêche les transactions concurrentes de voir des résultats partiels.
Chaque transaction est isolée des autres.
Implémenté par des protocoles de synchronisation bas-niveau sur les BDs…
Durabilité
Garantit que les mises à jour sur une BD peuvent survivre à un crash (BD,
machine, réseau)
En général, on utilise un fichier de log qui permet de faire des undos pour
revenir dans l'état avant le crash.
Modèles de transactions
Responsable : le
développeur de
bean
Il décide dans
son code du
begin, du
commit et du
abort
Ex: le banquier
Gestion des transactions déclarative
Bean-Managed Transactions
La transaction commence et se termine après que le message
a été reçu par le MDB.
On indique dans le descripteur de déploiement les
aknowledgement modes pour indiquer au container comment
accuser réception…
Container-Managed Transactions
La réception du message s'inscrit dans la même transaction
que les appels de méthodes métier du MDB. En cas de
problème, la transaction fait un rollback. Le container envoi
accusé de réception (message acknowledgement)
Pas de transaction
Le container accusera réception après réception. Quand
exactement, ce n'est pas précisé…
Transactions et Message-Driven Beans
Que choisir ?
Si on décide de ne pas laisser le container gérer les
transactions, on a pas de moyen de conserver le message
dans la queue de destination si un problème arrive.
On choisit Container-Managed 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 crée une
nouvelle transaction.
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 résumée.
Supports
Semblable à Required sauf que si une transaction
n'existe pas, elle n'est pas crée.
Si l'exécution du bean intervient dans une
transaction existante, il la rejoint néanmoins.
Mandatory
Une transaction doit exister lorsque le bean est
exécuté.
Si ce n'est pas le cas,
javax.ejb.TransactionRequiredException
est levée et renvoyée au client.
Si le client est local, c'est
javax.ejb.TransactionRequiredLocalException qui
est levée…
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'exécute, puis
la transaction est résumée.
Utiliser cet attribut lorsque les propriétés ACID
ne sont pas importantes…
Exemple : un bean qui fait des statistiques toutes
les dix minutes en parcourant une BD. On tolère
que les données 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 envoyée au client
si une transaction existe au moment de l'appel du
bean.
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
Le "I" de ACID !
L'isolation coûte cher en termes de
performances,
Nécessité de pouvoir régler le niveau
d'isolation entre transactions concurrentes !
Isolation de transaction
Lecture brouillée
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 fantôme
T1 lit quelques lignes satisfaisant certaines
conditions de recherche,
T2 insère plusieurs lignes satisfaisant ces mêmes
conditions de recherche,
Si T1 répète la lecture elle verra des lignes qui
n'existaient pas auparavant. Ces lignes sont
appelées des lignes fantômes.
Niveau d'isolation avec les EJB
Uncommited
Uniquement si on est sûr 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 donnée. On veut lire des données consistances,
mêmes si pendant qu'on les lisait quelqu'un était en train de
les modifier.
Lisent un snapshot des données commitées…
Niveau d'isolation par défaut de la plupart des BD (Oracle…)
Quel niveau utiliser
Repeatable
Lorsqu'on veut pouvoir lire et modifier des lignes,
les relire au cours d'une même transaction, sans
perte de consistance.
Serialisable
Pour les applications mission-critical qui nécessitent
un niveau d'isolation absolu, ACID 100% !
Attention ,les performances se dégradent à vitesse
grand V avec ce mode !
Comment spécifier ces niveaux ?
2. Stratégie optimiste
Peu de chance que ça foire, espère que tout va
bien se passe.
Néanmoins, si la BD détecte une collision, on fait
un rollback de la transaction.
Que faire dans le code EJB ???
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
Cardinalité
One-to-Many (1:N)
Un PDG et ses employés…
Many-to-Many (M:N)
Des étudiants suivent des cours…
Cardinalité
Relations 1:1
Schéma normalisé
Schéma dénormalisé
Choisir la directionalité ?
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 tôt dans ce chapitre.
Dans le ejbLoad() on appelle des finders…
Peut provoquer un énorme processus de chargement si le
graphe de relations est grand.
Lazy-loading
On ne charge les beans en relation que lorsqu'on essaie
d'accéder à l'attribut qui illustre la relation.
Tant qu'on ne demande pas quels cours il suit, le bean
Etudiant n'appelle pas de méthode finder sur le bean Cours.
Agrégation vs Composition et
destructions en cascade
Et le polymorphisme ?
Et l’héritage ?
Et EJB-QL ?
Héritage
Supporte le polymorphisme,
On alloue juste ce qu’il faut sur disque,
Excellente approche si on a pas une hiérarchie
trop profonde,
A éviter sinon…
Autres approches
Expressions
MEMBER OF
Sous-Requêtes
Fonctions sur chaînes, arithmétique
Fonctions sur chaînes, arithmétique (suite)
EJB QL : Quelques exemples (suite)
EJB QL : Quelques exemples (suite)
Bonnes pratiques de persistance
Michel Buffa (buffa@unice.fr), UNSA 2002
On manipule des données persistantes
Réfléchissez…
Est-ce plus avantageux pour un client normal de
recevoir des résultats distants par référence
NON ! Il vaut mieux les recevoir par valeur, sérialisés.
Performances : CMP
Bien réglés, les beans CMP sont bien plus performants que
les BMP,
Le container peut résoudre les relations en un seul, gros ordre
SQL,
On peut néanmoins 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 spécifié…
Avec CMP on contrôle tout…
Contrôle : BMP
Avec BMP on contrôle tout,
Mais les meilleurs containers ont des moteurs CMP très
puissants et paramétrables…
Portabilité : CMP
Indépendant de la base de données.
Choix entre BMP et CMP