-
Nous avons appris que les EJB de type entité permettent de représenter les données persistantes de l'application. Nous allons maintenant voir qu'il y a, en fait, deux façons de gérer cette persistance.
Dans le chapitre précédent, nous avons écrit les méthodes qui synchronisent les données membres de notre EJB avec notre base de données. C'est ce que l'on appelle la persistance gérée par le composant ( BMP : Bean Managed Persistance ).
Au lieu d'écrire nous mêmes ces méthodes, nous pouvons laisser le conteneur se charger des appels à la base de données : c'est ce qu'on appelle la persistance gérée par le conteneur ( CMP : Container Managed Persistance ).
Cette façon de faire permet :
- De supprimer tout le code lié aux bases de données de votre source ( accès, requêtes et traitements ).
- D'être indépendant de la base de données utilisée.
Afin de bien vous montrer les différences entre les deux approches, nous allons reprendre l'exemple du chapitre précédent en laissant le conteneur gérer la persistance.
-
La structure de la table CLIENTS et la façon de configurer la base de données sont les mêmes.
-
-
Identique à celle vue dans le chapitre précédent.
Client.java
|
1 2 3 4 5 6 7 8 9 10
11 12 13 14
|
package crm_cmp;
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
public interface Client extends EJBObject {
public String getNom() throws RemoteException;
public String getPrenom() throws RemoteException;
public void setPrenom(String prenom) throws RemoteException;
}
|
|
Java2html
|
-
Identique à celle vue dans le chapitre précédent.
ClientHome.java
|
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16
|
package crm_cmp;
import java.io.Serializable;
import java.rmi.RemoteException;
import javax.ejb.*;
import java.util.*;
public interface ClientHome extends EJBHome {
public Client create(String codeClient, String nom, String prenom) throws RemoteException, CreateException;
public Client findByPrimaryKey(String codeClient) throws RemoteException, FinderException;
public Collection findByNom(String nom) throws RemoteException, FinderException;
}
|
|
Java2html
|
Nous n'implémenterons pas le code de nos méthodes finder dans notre EJB car il sera généré par l'utilitaire GenIC. Nous aurons juste à spécifier la clause WHERE de la méthode findByNom() dans le descripteur de déploiement.
-
ClientBean.java
|
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86
|
package crm_cmp;
import java.sql.*;
import javax.sql.*;
import java.util.*;
import javax.ejb.*;
import javax.naming.*;
public class ClientBean implements EntityBean {
// Données du client
public String codeClient;
public String nom;
public String prenom;
// Contexte de l'EJB
private EntityContext context;
// Fonction promise dans l'interface distante
public String getNom() {
return nom;
}
// Fonction promise dans l'interface distante
public String getPrenom() {
return prenom;
}
// Fonction promise dans l'interface distante
public void setPrenom(String prenom) {
this.prenom = prenom;
}
// Crée le composant et le sauvegarde dans la base de données avec un insert
public String ejbCreate(String codeClient, String nom, String prenom) throws CreateException {
// renseigne les propriétés du composant
this.codeClient = codeClient;
this.nom = nom;
this.prenom = prenom;
return null;
}
public void ejbPostCreate(String codeClient, String nom, String prenom) {
// Ne fait rien
}
// Cette fonction permet de supprimer un composant
public void ejbRemove() throws RemoveException {
}
// Appelé juste après la création ou la réactivation du composant
//
public void setEntityContext(EntityContext context) {
this.context = context;
}
// Appellé lorsque le composant est enlevé
public void unsetEntityContext() {
this.context = null;
}
// appellé lorsque l'objet redevient actif
public void ejbActivate() {
}
// appellé lorsque l'objet devient passif
public void ejbPassivate() {
}
// Cette fonction est une fonction de synchronisation, elle est appellée par le conteneur
// lorsqu'il veut lire les informations de l'EJB depuis le support de stockage
public void ejbLoad() {
}
// Cette fonction est une fonction de synchronisation, elle est appellée par le
// conteneur lorsqu'il veut sauvegarder les informations de l'EJB dans le support de stockage
public void ejbStore() {
}
}
|
|
Java2html
|
- ejbCreate()
Etant donné que la persistance est gérée au niveau du conteneur, ce que retourne la méthode ejbCreate() est ignoré. C'est pour cette raison qu'elle retourne null.
L'insertion effective des champs dans la base de données ne sera faite qu'après l'invocation de la méthode ejbCreate().
- ejbRemove()
La méthode ejbRemove() est appelée par le conteneur lorsqu'un client appelle la méthode remove(). Si vous avez besoin d'effectuer des traitements avant destruction, implémentez les ici.
- ejbLoad()
Le conteneur détermine le moment où il doit rafraîchir l'état de l'entité à partir de la base de données. Lorsque l'action devient nécessaire, le conteneur sélectionne la ligne voulue dans la base, il assigne les valeurs des colonnes de cette donnée aux variables d'instance, puis il invoque ejbLoad().
- ejbStore()
Lorsque le conteneur détermine qu'il est nécessaire de synchroniser la base de données avec l'état courant du composant, il commence par invoquer la méthode ejbStore(), puis il met à jour la base de données avec les valeurs des variables d'instance de l'EJB.
-
-
Par rapport à notre précédent descripteur de déploiement, la différence se situe au niveau de persistance-type. Comme vous pouvez le constater, nous avons mis comme valeur Container ce qui, bien sur, défini que notre persistance sera gérée par le conteneur.
Nous avons aussi déclaré toutes nos variables d'instance comme cmp-field, elles seront donc tous stockées dans la base de données.
Puis, avec la balise primkey-field, on définit quel sera le champs qui sera la clé primaire.
| ejb-jar.xml |
|
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>
<description>Déscripteur de déploiement pour l'EJB client</description>
<display-name>EJB Client</display-name>
<enterprise-beans>
<entity>
<description>EJB Client ( CMP )</description>
<ejb-name>Client</ejb-name>
<home>crm_cmp.ClientHome</home>
<remote>crm_cmp.Client</remote>
<ejb-class>crm_cmp.ClientBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>
<cmp-field>
<field-name>codeClient</field-name>
</cmp-field>
<cmp-field>
<field-name>nom</field-name>
</cmp-field>
<cmp-field>
<field-name>prenom</field-name>
</cmp-field>
<primkey-field>codeClient</primkey-field>
</entity>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>Client</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
|
-
Ce descripteur de déploiement, en plus de définir le nom JNDI, va définir :
- Quelle connexion le conteneur doit utiliser pour se connecter à la base de données (
conMySQL_CRM ).
- Le nom de la table dans laquelle doivent être stockées les valeurs des variables d'instance de notre EJB (
CLIENTS ).
- Quel champs de la table
CLIENTS doit acceuilir la valeur de la variable d'instance codeClient ( CODE_CLIENT ).
- Quel champs de la table
CLIENTS doit acceuilir la valeur de la variable d'instance nom ( NOM ).
- Quel champs de la table
CLIENTS doit acceuilir la valeur de la variable d'instance prenom ( PRENOM ).
- Que la méthode
findByNom() retourne les EJB correspondant au résultat d'une requête sur la table CLIENTS dont la clause where est 'where NOM = ?'.
| jonas-ejb-jar.xml |
|
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE jonas-ejb-jar PUBLIC "-//ObjectWeb//DTD JOnAS 2.4//EN" "http://www.objectweb.org/jonas/dtds/jonas-ejb-jar_2_4.dtd">
<jonas-ejb-jar>
<jonas-entity>
<ejb-name>Client</ejb-name>
<jndi-name>MyClient</jndi-name>
<jdbc-mapping>
<jndi-name>conMySQL_CRM</jndi-name>
<jdbc-table-name>CLIENTS</jdbc-table-name>
<cmp-field-jdbc-mapping>
<field-name>codeClient</field-name>
<jdbc-field-name>CODE_CLIENT</jdbc-field-name>
</cmp-field-jdbc-mapping>
<cmp-field-jdbc-mapping>
<field-name>nom</field-name>
<jdbc-field-name>NOM</jdbc-field-name>
</cmp-field-jdbc-mapping>
<cmp-field-jdbc-mapping>
<field-name>prenom</field-name>
<jdbc-field-name>PRENOM</jdbc-field-name>
</cmp-field-jdbc-mapping>
<finder-method-jdbc-mapping>
<jonas-method>
<method-name>findByNom</method-name>
</jonas-method>
<jdbc-where-clause>where NOM = ?</jdbc-where-clause>
</finder-method-jdbc-mapping>
</jdbc-mapping>
</jonas-entity>
</jonas-ejb-jar>
|
-
Aucune différence avec ce que l'on a vu dans les chapitres précédents. Voir le script fourni avec les sources.
-
Aucune différence avec ce que l'on a vu dans les chapitres précédents. Voir le script fourni avec les sources.
-
Le code du client de notre EJB est identique à celui du précédent chapitre. En effet, seuls les méthodes qui permettent l'interaction entre l'Enterprise JavaBean et notre base données ont été modifiées et elles ne sont jamais appelées directement par le client.
-
Pour réaliser la compilation, le packaging et le déploiement, nous allons utilisé le script build.bat que vous trouverez dans le répertoire "C:\java\dev\Client_CMP".
Ce script effectuera la compilation, le packaging et le déploiement de notre ejb et de notre client.
-
Déployons notre EJB et testons le avec notre application.
- cd C:\java\dev\Client_CMP
- build
- jonas start
- cd C:\java\dev\build
- jclient crm_cmp.Test
Voici le résultat :
Nom du client LGUEVARRA : GUEVARRA
Liste des clients qui ont pour nom TRAUMAT :
->Stephane
->Pierrre
Si on fait un select sur notre table CLIENTS, on obtient le résultat suivant :
| CODE_CLIENT |
NOM |
PRENOM |
| STRAUMAT |
TRAUMAT |
Stephane |
| LGUEVARRA |
GUEVARRA |
Loreen |
| PTRAUMAT |
TRAUMAT |
Pierre |
On voit bien que les insertions, les selections, les suppressions et les mises à jour se sont bien faites.
-
Comme vous avez pu le constater, la persistance gérée par le conteneur permet :
- De supprimer tout le code lié aux bases de données de votre source (accès, requêtes et traitements).
- De ne plus avoir à gérer les relations entre les EJB entités.
- D'être indépendant de la base de données utilisée.
- De réduire le nombre de lignes de codes (et donc de réduire le nombre de bug).
- De réduire la complexité de vos applications.
Bien entendu, tous ces avantages ont une contre-partie : les performances. Il faut donc les utiliser avec beaucoup de précautions.
|
|