15 Développement d'application de
base de données en Java
27/02/22 © Robert Godin. Tous droits réservés. 2
Patron d'architecture en couche (layer)
Couche présentation
Couche contrôle (coordonnateur d'application)
Couche domaine d'application (ou métier)
Couche de services.
– persistance
– transaction
– communication
– sécurité
– etc.
15.1 Application Java/JDBC client-serveur
R é s e a u
L o g i c i e l i n t e r m é d i a i r e
P i l o t e d e t é l é c o m m u n i c a t i o n
P r o g r a m m e d 'a p p l i c a t i o n
L o g i c i e l i n t e r m é d i a i r e
P i l o t e d e t é l é c o m m u n i c a t i o n
S G B D
C l i e n t S e r v e u r
B D
P r o g r a m m e d 'a p p l i c a t i o n : - p r é s e n t a t i o n
- c o n t r ô l e
- d o m a i n e d 'a p p l i c a t i o n
S G B D
- p e r s i s t e n c e
- p a r t i e d u d o m a i n e d 'a p p l i c a t i o n ?
27/02/22 © Robert Godin. Tous droits réservés. 4
Cas d ’utilisation EnregistrerPrêts
Commis au prêt Système
1. Le commis invoque l'écran d'enregistrement du prêt
2. Le système demande la saisie de l'identificateur de l'utilisateur
3. Le commis saisit l'identificateur de l'utilisateur à l'aide de la carte de membre ou manuellement
4. Le système affi che le nombre de prêts en cours et demande de saisir l'identificateur de l'exemplaire.
5. Le commis entre l'identificateur de l'exemplaire à l'aide du lecteur optique ou manuellement
6. Le système enregistre le prêt, affi che un message
d'acquiescement.
Cas de test pour scénario normal
27/02/22 © Robert Godin. Tous droits réservés. 6
Cas d ’exception : nombre maximal
d'emprunts (ici 2) atteint
Cas d ’exception : exemplaire
non disponible
27/02/22 © Robert Godin. Tous droits réservés. 8
Cas d'utilisation et classes métiers concernées
Personne nom : String prénom : String
Membre
téléphoneRésidence : String nbMaxPrêts : Integer = 5 duréeMaxPrêts : Integer = 7
PrêtEnCours Employé
{UNIQUE : codeMatricule}
codeMatricule : String
catégorieEm ployé : enum (b ibliothécaire, co mm is ) catégorieUtilisateur
Exemplaire {UNIQUE: idExemplaire}
idExemplaire : String dateAchat : Date
statut : enum(prêté, disponible, retiré)
Prêt datePrêt : Date
1 0..*
1 0..*
Utilisateur {UNIQUE :idUtilisateur}
idUtilisateur : String
motPasse : String 11 0..*0..*
{disjointe, complète}
{disjointe, complète}
EnregistrerPrêts
(from PackageCasServicePrêt)
Patron courtier BD : classes du
programme Java et tables concernées
Membre
té léph oneRésidence : String nbMaxPrêts : Integer = 5 duréeMaxPrêts : Integer = 7
PrêtEnCours Utilisateur
idUtilisateur : String m otPass e : String catégorie : String lesPrêts : Vector
CourtierBDUtilisateur
ch erch erVari ables StatiquesDeMem bre() ch erch erUtili sateu rParIdUti lisateur()
CourtierBDPrêtsEnCou rs chercherLesPrêtsEnCours() insérerPrêtEnCours ()
Courtie rBDExem plaire che rche rExem plaireParId Exem plaire() Prêt
datePrêt : Date
lExem plaire : Exem plaire lUtilisateur : Utilisateur
Exem plaire idExem plaire : String statut : String Person ne
nom : Stri ng préno m : Stri ng
Em ployé {UNIQUE : codeMatricule}
codeMatricule : String
catégorieEm ployé : enum (bibliothécaire, com m is)
~ Data Access Object
(DAO) + Domain Data
Transfer Object
27/02/22 © Robert Godin. Tous droits réservés. 10
Classe Java pour Personne
package ExemplesJDBC.SyLeRat;
public class Personne { protected String nom;
protected String prénom;
public Personne(String nom,String prénom) { this.nom = nom;
this.prénom = prénom;
}
public String getNom(){return nom;}
public String getPrénom(){return prénom;}
public void setNom(String nom){this.nom = nom;}
public void setPrénom(String prénom){this.prénom = prénom;}
}
Lecteurs/modifieurs pour attributs
(peut en faire un Java Bean)
Classe Java pour Utilisateur
package ExemplesJDBC.SyLeRat;
import java.util.*;
public class Utilisateur extends Personne { protected String idUtilisateur;
protected String motPasse;
protected String catégorie;
protected Vector lesPrêts; // Association avec Prêt // NB Ce constructeur de crée pas lesPrêts
public Utilisateur(String idUtilisateur, String motPasse, String nom, String prénom, String catégorie){
super(nom,prénom);
this.idUtilisateur = idUtilisateur;
this.motPasse = motPasse;
this.catégorie = catégorie;
}
public String getIdUtilisateur(){return idUtilisateur;}
public String getMotPasse(){return motPasse;}
public String getCatégorie(){return catégorie;}
public Vector getLesPrêts(){return lesPrêts;}
public int getNbPrêtsEnCours(){
Enumeration enumerationPrêts = lesPrêts.elements();
int nbPrêtsEnCours = 0;
while (enumerationPrêts.hasMoreElements()){
Prêt unPrêt = (Prêt)enumerationPrêts.nextElement();
if (unPrêt instanceof PrêtEnCours){
nbPrêtsEnCours++;
} }
Lecteur pour donnée dérivée
Lecteurs/modifieurs
pour naviguer les
associations
27/02/22 © Robert Godin. Tous droits réservés. 12
Classe Java pour Membre
package ExemplesJDBC.SyLeRat;
import java.util.*;
public class Membre extends Utilisateur { private static int nbMaxPrêts;
private static int duréeMaxPrêt;
private String téléphoneRésidence;
public Membre(String idUtilisateur, String motPasse, String nom, String prénom, String catégorie, String téléphoneRésidence){
super(idUtilisateur, motPasse, nom, prénom, catégorie);
this.téléphoneRésidence = téléphoneRésidence;
}
public static int getNbMaxPrêts(){return nbMaxPrêts;}
public static int getDuréeMaxPrêt(){return duréeMaxPrêt;}
public static void setNbMaxPrêts(int leNbMaxPrêts){nbMaxPrêts = leNbMaxPrêts;}
public static void setDuréeMaxPrêts(int laDuréeMaxPrêt){duréeMaxPrêt = laDuréeMaxPrêt;}
public void setTéléphoneRésidence(String téléphoneRésidence) {this.téléphoneRésidence = téléphoneRésidence;}
public String getTéléphoneRésidence(){return téléphoneRésidence;}
public int getNbRetards(){
Enumeration enumerationPrêts = lesPrêts.elements();
int nbRetards = 0;
Calendar maintenant = Calendar.getInstance(); // Calendrier avec date actuelle // Soustrait ensuite la durée maximale en jours pour obtenir la date minimale // avant laquelle il y a un retard
maintenant.add(Calendar.DATE,-duréeMaxPrêt);
java.sql.Date dateMinSansRetard = new java.sql.Date(maintenant.getTime().getTime());
while (enumerationPrêts.hasMoreElements()){
Prêt unPrêt = (Prêt)enumerationPrêts.nextElement();
if (unPrêt instanceof PrêtEnCours){
if (dateMinSansRetard.after(unPrêt.getDatePrêt())){
nbRetards++;
} } }
return nbRetards;
}
public boolean conditionsPrêtAcceptées(){
return (this.getNbRetards() == 0 && this.getNbPrêtsEnCours() < nbMaxPrêts);
} }
Attributs et méthodes
static pour attributs de
classe (ou singleton)
Classe Java pour Employé
package ExemplesJDBC.GererPrets;
import java.util.*;
public class Employé extends Utilisateur { private String codeMatricule;
private String catégorieEmployé;
public Employé(String idUtilisateur, String motPasse, String nom,
String prénom, String catégorie, String codeMatricule, String catégorieEmployé){
super(idUtilisateur, motPasse, nom, prénom, catégorie);
this.codeMatricule = codeMatricule;
this.catégorieEmployé = catégorieEmployé;
}
public String getCodeMatricule(){return codeMatricule;}
public String getCatégorieEmployé(){return catégorieEmployé;}
public void setCodeMatricule(String codeMatricule) {this.codeMatricule = codeMatricule;}
public void setCatégorieEmployé(String catégorieEmployé) {this.catégorieEmployé = catégorieEmployé;}
}
27/02/22 © Robert Godin. Tous droits réservés. 14
Classe Java pour Prêt
package ExemplesJDBC.SyLeRat;
import java.sql.Date;
public class Prêt {
protected Utilisateur lUtilisateur;
protected java.sql.Date datePrêt;
protected Exemplaire lExemplaire;
public Prêt(Utilisateur lUtilisateur,java.sql.Date datePrêt, Exemplaire lExemplaire) { this.lUtilisateur = lUtilisateur;
this.datePrêt = datePrêt;
this.lExemplaire = lExemplaire;
}
public java.sql.Date getDatePrêt(){return datePrêt;}
public String getIdExemplaire(){return lExemplaire.getIdExemplaire();}
public String getIdUtilisateur(){return lUtilisateur.getIdUtilisateur();}
}
Classe Java pour PrêtEnCours
package ExemplesJDBC.GererPrets;
public class PrêtEnCours extends Prêt {
public PrêtEnCours(Utilisateur lUtilisateur,java.sql.Date datePrêt, Exemplaire lExemplaire) {
super(lUtilisateur,datePrêt,lExemplaire);
}
// Le constructeur suivant ne construit pas le lien vers Exemplaire public PrêtEnCours(Utilisateur lUtilisateur,java.sql.Date datePrêt) { super(lUtilisateur,datePrêt,null);
}
}
27/02/22 © Robert Godin. Tous droits réservés. 16
Classe Java pour Exemplaire
package ExemplesJDBC.SyLeRat;
public class Exemplaire {
private String idExemplaire;
private String statut;
public Exemplaire(String idExemplaire,String statut) { this.idExemplaire = idExemplaire;
this.statut = statut;
}
public String getStatut(){return statut;}
public String getIdExemplaire(){return idExemplaire;}
}
CourtierBDUtilisateur
package ExemplesJDBC.GererPrets;
import java.sql.*;
import java.util.*;
public class CourtierBDUtilisateur{
private Connection uneConnection;
// Constructeur pour connexion passée par le créateur public CourtierBDUtilisateur(Connection laConnection){
this.uneConnection = laConnection;
}
…
public Utilisateur chercherUtilisateurParIdUtilisateur(String idUtilisateur) // Retourne un objet Membre ou un Employé selon le cas
throws Exception {
// Verrouillage de l'utilisateur pour sérialisabilité (Oracle mode READ COMMITTED) PreparedStatement unEnoncéSQL = uneConnection.prepareStatement
("SELECT motPasse,nom,prénom,catégorieUtilisateur,téléphoneRésidence,codeMatricule,catégorieEmployé "+
"FROM Membre m, Utilisateur u, Employé e WHERE u.idUtilisateur = ? AND "+
"u.idUtilisateur = m.idUtilisateur (+) AND "+
"u.idUtilisateur = e.idUtilisateur (+) FOR UPDATE");
unEnoncéSQL.setString(1,idUtilisateur);
ResultSet résultatSelect = unEnoncéSQL.executeQuery();
if (résultatSelect.next ()){
if (résultatSelect.getString ("catégorieUtilisateur").equals("membre")){
Membre leMembre = new Membre(
idUtilisateur,résultatSelect.getString ("motPasse"),
résultatSelect.getString ("nom"),résultatSelect.getString ("prénom"), résultatSelect.getString ("catégorieUtilisateur"),
27/02/22 © Robert Godin. Tous droits réservés. 18
Diagramme de séquence pour CourtierBDUtilisateur
: ContrôleEnregistrerPrêts : CourtierBDUtilisateur
:java.sql .Connection
:java.sql.Statement
: Membre
: Em pl oyé 2. chercherUtilisateur(idUtilisateur)
1. «create»(uneConnection)
3. prepareStatement()
4. executeQuery()
5. [catégorie = 'membre']«create»
7. unU til isateur
6. [catégorie='employé']«create»
Classe UsineConnection
package ExemplesJDBC.GererPrets;
import java.sql.*;
public class UsineConnection { public UsineConnection() {}
public Connection getConnectionSansAutoCommit(
String nomPilote, // "oracle.jdbc.driver.OracleDriver" pour Oracle
String URLBD, // exemple : "jdbc:oracle:thin:@localhost:1521:ora817i"
String authorizationID, String password)
throws Exception {
Class.forName (nomPilote);
Connection uneConnection = DriverManager.getConnection (URLBD, authorizationID,password);
uneConnection.setAutoCommit(false);
return uneConnection;
}
public Connection getConnection(
String nomPilote, // "oracle.jdbc.driver.OracleDriver" pour Oracle
String URLBD, // exemple : "jdbc:oracle:thin:@localhost:1521:ora817i"
String authorizationID, String password)
throws Exception {
Class.forName (nomPilote);
Connection uneConnection = DriverManager.getConnection (URLBD, authorizationID,password);
return uneConnection;
27/02/22 © Robert Godin. Tous droits réservés. 20
Courtier CourtierBDPrêtEnCours : chercherLesPrêtsEnCours
package ExemplesJDBC.GererPrets;
import java.sql.*;
import java.util.*;
public class CourtierBDPrêtEnCours { private Connection uneConnection;
…
public void chercherLesPrêtsEnCours(Utilisateur unUtilisateur) // Dématérialiser les PrêtEnCours d'un Utilisateur
throws Exception{
// Verrouiller la table des prêts en cours pour sérialisabilité // (Oracle mode READ COMMITTED)
PreparedStatement unEnoncéLock = uneConnection.prepareStatement(
"LOCK TABLE PrêtEnCours IN SHARE ROW EXCLUSIVE MODE");
unEnoncéLock.execute();
unEnoncéLock.close();
PreparedStatement unEnoncéSQL = uneConnection.prepareStatement ("SELECT datePrêt,idExemplaire "+
"FROM PrêtEnCours WHERE idUtilisateur = ? " );
String idUtilisateur = unUtilisateur.getIdUtilisateur();
unEnoncéSQL.setString(1,idUtilisateur);
ResultSet résultatSelect = unEnoncéSQL.executeQuery();
// lesPrêts contiendra la collection des objets PrêtEnCours Vector lesPrêts = new Vector();
while (résultatSelect.next ()){
PrêtEnCours unPrêt = new PrêtEnCours(unUtilisateur,résultatSelect.getDate(1));
lesPrêts.addElement(unPrêt);
}
// Faire les références inverses ! unUtilisateur.setLesPrêts(lesPrêts);
unEnoncéSQL.close();
}
… }
Matérialisation d ’un PrêtEnCours : insérerPrêtEnCours
package ExemplesJDBC.GererPrets;
import java.sql.*;
import java.util.*;
public class CourtierBDPrêtEnCours { private Connection uneConnection;
…
public void insérerPrêtEnCours (PrêtEnCours unPrêtEnCours) // Matérialise un nouveau PrêtEnCours dans la BD
throws Exception, SQLException {
PreparedStatement unEnoncéSQL = uneConnection.prepareStatement ("INSERT INTO PrêtEnCours(idExemplaire,idUtilisateur)"+
"VALUES(?,?)");
unEnoncéSQL.setString(1,unPrêtEnCours.getIdExemplaire());
unEnoncéSQL.setString(2,unPrêtEnCours.getIdUtilisateur());
//NB la date est générée automatiquement par le serveur de BD (default sysdate) // et le statut est modifié par un TRIGGER
int n = unEnoncéSQL.executeUpdate();
unEnoncéSQL.close();
if (n != 1){throw new Exception("Insertion dans PrêtEnCours a échoué");}
}
}
27/02/22 © Robert Godin. Tous droits réservés. 22
Enjeux de la conception des courtiers
Granularité des courtiers
Granularité de
matérialisation/dématérialisation
– minimiser les appels au serveur de BD
– limiter le volume de données à
transférer
Classe de contrôle
ControleEnregistrerPrets
package ExemplesJDBC.GererPrets;
/* Classe de contrôle simple pour EnregistrerPrêts * Interface à l'utilisateur minimaliste
* NB Vérifie les conditions de prêt et le statut de l'exemplaire au niveau du programme client */
import java.sql.*;
import javax.swing.JOptionPane;
import java.util.*;
class ControleEnregistrerPrets {
public static void main (String args []) throws Exception { // Création d'une Connection globale pour l'application UsineConnection uneUsineConnection = new UsineConnection();
Connection uneConnection = uneUsineConnection.getConnectionSansAutoCommit(
"oracle.jdbc.driver.OracleDriver",
"jdbc:oracle:thin:@localhost:1521:ora817i", "clerat","oracle");
try{
// Dématérialiser l'Utilisateur et ses PrêtsEnCours Membre unMembre = null;
String idUtilisateur =
JOptionPane.showInputDialog("Entrez l'identificateur de l'utilisateur: ");
// Création du courtier et dématérialisation de l'Utilisateur
CourtierBDUtilisateur unCourtierBDUtilisateur = new CourtierBDUtilisateur(uneConnection);
Utilisateur unUtilisateur =
unCourtierBDUtilisateur.chercherUtilisateurParIdUtilisateur(idUtilisateur);
27/02/22 © Robert Godin. Tous droits réservés. 24
uneTransaction
: Commis au prêt :
ContrôleEnregistrerPrêts :
CourtierBDUtilisateur
: CourtierBDPrêtsEnCours
:
CourtierBDExemplaire : Usin eConnection
uneConnection 2. getConnexionSansAutoCommit( )
4. uneConnection
9. «create»(uneConnection) 10 . chercherLesPrêtsEnCours(un Utilisateur )
18. insérerPrêtEnCou rs (unPrêtEnCours) 7. chercherUtilisateur(idUtilisateur)
12. chercherVariablesStatiquesDeMembre( ) 6. «cre ate»(uneConnection)
15. «create»(uneConnection) 16. chercherExem plaire (i dExemplaire )
3. «create»
8. prepareStatement()
11. prepareStatement()
13. prepareStatement()
17. prepareStatement()
20. commit() 21. close() 1. créerNouveauPrêt()
5 . entrer(idUtilisateur)
14. entrer(i dExempl aire)
19. prepapreStatement()
uneTransaction : Commis au prêt :
ContrôleEnregistrerPrêts : CourtierBDUtilisateur
: CourtierBDPrêtsEnCours
: CourtierBDExemplaire
: Usin eConnection
uneConnection 2. getConnexionSansAutoCommit( )
4. uneConnection
9. «create»(uneConnection) 10 . chercherLesPrêtsEnCours(un Utilisateur ) 7. chercherUtilisateur(idUtilisateur)
12. chercherVariablesStatiquesDeMembre( ) 6. «cre ate»(uneConnection)
15. «create»(uneConnection)
3. «create»
8. prepareStatement()
11. prepareStatement()
13. prepareStatement() 1. créerNouveauPrêt()
5 . entrer(idUtilisateur)
14. entrer(idExemplaire)
15.1.1 Enjeux de conception d'une application Java/JDBC
Dépendance
au temps de
réflexion
27/02/22 © Robert Godin. Tous droits réservés. 26
Limiter les verrouillages ?
Limiter la durée des transactions
Contraintes de sérialisabilité ?
27/02/22 © Robert Godin. Tous droits réservés. 28
Vérification des contraintes par le serveur
Non
sérialisabilité
perçue par T2
Contrôle de concurrence optimiste par estampillage explicite
Lecture en une première transaction
– Note l’estampille courante (ou numéro de version, …)
Écriture en une deuxième transaction distincte
– Vérifie si l’état a changé depuis la lecture
Si non, met à jour les données et l’estampille
Si oui, annulation
Ne bloque pas les objets lus
Populaire dans les applications Web
27/02/22 © Robert Godin. Tous droits réservés. 30
Réduire l'interactivité
Nom: EnregistrerPrêtsSimple
Description courte : Enregistrer les prêts en un aller-retour au système Type: Interactif
Description : Ce cas d'utilisation est déclenché par le commis au prêt suite à une requête d'un membre ou d'un employé et lui permet d'enregistrer un prêt en un aller-retour au système.
Exigence d'intégrité : la séquence constitue une transaction Séquence normale d'interaction :
Commis au prêt Système
1. Le commis invoque l'écran d'enregistrement du prêt
2. Le système demande la saisie de l'identificateur de l'utilisateur et de l’exemplaire
3. Le commis saisit l'identificateur de l'utilisateur à l'aide de la carte de membre ou manuellement et entre l'identificateur de l'exemplaire à l'aide du lecteur optique ou manuellement.
4. Le système enregistre le prêt, affi che un message
d'acquiescement.
ControleEnregistrerPretsSimple
uneTransaction : Commis au prêt :
ContrôleEnregistrerPrêts
: CourtierBDPrêtsEnCours :
UsineConnection
uneConnection 1. créerNouveauPrêt()
5. entrer(idUtilisate ur, idExempl aire)
6. «create»(uneConnection) 7. insérerPrêtEnCours (unPrêtEnCours)
2. getConnexion( )
4. uneConnection 3. «create»
9. close()
8. prepapreStatem ent()
27/02/22 © Robert Godin. Tous droits réservés. 32 public typeRetour nomMéthodeCourtier(listeParamètres)
throws Exception {
Connection uneConnection = uneUsineConnection.getConnection…
// Utiliser uneConnection
…
uneConnection.close();
}
Libérer la connexion entre les appels
Transaction ne peut chevaucher les appels
Ouverture/fermeture couteuse
– Solution : connection pooling (JDBC 2)
15.1.2 Gestion de la sécurité
Qui gère l ’idUtilisateur et le mot de passe ?
– par les données : le SGBD
– par les traitements : le programme
client
27/02/22 © Robert Godin. Tous droits réservés. 34
ControleEnrPretsSecuriteParDonnees
package ExemplesJDBC.GererPrets;
/* Classe de contrôle simple pour EnregistrerPrêts * Interface à l'utilisateur minimaliste
* NB Vérifie les conditions de prêt et le statut de l'exemplaire au niveau du programme client
*/ import java.sql.*;
import javax.swing.JOptionPane;
import java.util.*;
class ControleEnrPretsSecuriteParDonnees {
public static void main (String args []) throws Exception { String idCommis =
JOptionPane.showInputDialog("Entrez l'identificateur du commis au prêt: ");
String motDePasse =
JOptionPane.showInputDialog("Entrez le mot de passe : ");
// Création d'une Connection à partir du idCommis et de son motDePasse UsineConnection uneUsineConnection = new UsineConnection();
Connection uneConnection = uneUsineConnection.getConnectionSansAutoCommit(
"oracle.jdbc.driver.OracleDriver",
"jdbc:oracle:thin:@localhost:1521:ora817i", idCommis, motDePasse);
try{
// Dématérialiser l'Utilisateur et ses PrêtsEnCours
…
// Le reste du code est identique à ControleEnregistrerPrets
ControleEnrPretsSecuriteParTraitement
package ExemplesJDBC.GererPrets;
/* Classe de contrôle pour EnregistrerPrêts * Sécurité «par les traitements»
* Interface à l'utilisateur minimaliste
* NB Vérifie les conditions de prêt et le statut de l'exemplaire au niveau du programme client */
import java.sql.*;
import javax.swing.JOptionPane;
import java.util.*;
class ControleEnrPretsSecuriteParTraitement {
public static void main (String args []) throws Exception {
// Création d'une Connection avec un authorizationID SQL indépendant du idCommis UsineConnection uneUsineConnection = new UsineConnection();
Connection uneConnection = uneUsineConnection.getConnectionSansAutoCommit(
"oracle.jdbc.driver.OracleDriver",
"jdbc:oracle:thin:@localhost:1521:ora817i", "clerat", "oracle");
try{
// Authentifier le commis au prêt (en utilisant la table Utilisateur) String idCommis =
JOptionPane.showInputDialog("Entrez l'identificateur du commis au prêt: ");
CourtierBDUtilisateur unCourtierBDUtilisateur = new CourtierBDUtilisateur(uneConnection);
Utilisateur lUtilisateur =
unCourtierBDUtilisateur.chercherUtilisateurParIdUtilisateur(idCommis);
if (!(lUtilisateur instanceof Employé)){
JOptionPane.showMessageDialog(null,"Pas un employé :"+idCommis);
}else {
Employé leCommis = (Employé)lUtilisateur;
if (!(leCommis.getCatégorieEmployé().equals("commis"))){
JOptionPane.showMessageDialog(null,"Pas un commis au prêt:"+idCommis);
} else {
27/02/22 © Robert Godin. Tous droits réservés. 36
15.1.3 Façade pour les services de la couche application
Membre PrêtEnCours
Utilisateur
CourtierBDUtilisateur CourtierBDPrêtsEnCours CourtierBDExemplaire Prêt
Exemplaire Personne
ControleEnregistrerPretsAvecFacade
FacadeEnregistrerPrets
UsineConnection Connection
Diagramme de séquence pour
ControleEnregistrerPretAvecFacade
: ControleEnregistrerPretsAvecFacade : FacadeEnregistrerPrets : UsineConnection uneConnection
3. chercherOTDUtilisateurPrets()
4. getStatutExemplaire()
5. insererPretEnCours( )
6. confirmerTransaction( ) 1. «create»
1.1. getConnexionSansAuto Commit( )
1.1.1. «create»
2. u neConnectio n
7. commit() 8. close()
Dépendance réduite
27/02/22 © Robert Godin. Tous droits réservés. 38
Patron d'objet de transfert de données (OTD)
uneClasseControle unOTD uneClasseFacade
1. getOTD()
3. getPropriété1() 4. getPropriété2() 5. getPropriété3() etc.
2. unOTD
ControleEnregistrerPretsSimpleAvecFacade
:ControleEnregistrerPretsSimpleAvecFacade :FacadeEnregistrerPretsSimple : UsineC onne ction uneConnection 1. «create»
2. insererPretEnCours(idUtilisateur,idExemplaire)
3. getConn ection() 5. uneCon nection
6. close()
4. «create»
Connexion libérée
27/02/22 © Robert Godin. Tous droits réservés. 40
15.2 Développement d'applications Web par servlet Java
F u r e t e u r W e b : - p r é s e n t a t i o n
S G B D
- p e r s i s t e n c e
- p a r t i e d u d o m a i n e d 'a p p l i c a t i o n ?
C l i e n t m i n c e S e r v e u r B D
S e r v e u r d 'a p p l i c a t i o n : - c o n t r ô l e
- d o m a i n e d 'a p p l i c a t i o n
S e r v e u r d ' a p p l i c a t i o n
15.2.1 Principe de base du Web : le protocole HTTP et le langage de
présentation HTML
F u r e t e u r W e b S e r v e u r W e b
R e q u ê t e H T T P
R é p o n s e H T T P
27/02/22 © Robert Godin. Tous droits réservés. 42
15.2.2 Développement de servlet Java
S e r v e u r d 'a p p l i c a t i o n ( W e b )
C o n t e n e u r à s e r v l e t
2 . L e s e r v e u r t é l é c h a r g e l a F O R M H T M L
F u r e t e u r W e b
s e r v l e t J a v a
3 . L e f u r e t e u r e n v o i e d e s
p a r a m è t r e s ( H T T P P O S T ) 4 . L e s e r v e u r d é l è g u e l ' a p p e l a u c o n t e n e u r à s e r v l e t 1 . L e f u r e t e u r I n v o q u e l ' é c r a n
d e s a i s i e ( H T T P G E T )
5 . L e c o n t e n e u r à s e r v l e t d é m a r r e u n f i l d e l a s e r v l e t
7 . L a s e r v e l t p r o d u i t l a r é p o n s e H T T P q u i e s t r e t o u r n é e a u f u r e t e u r
S e r v e u r B D
6 . L a s e r v e l t f a i t a p p e l a u
s e r v e u r d e B D B D
F O R M H T M L
Diagramme de séquence de l'invocation de la servlet
ServletEnregistrerPretSimpleFacade
unFureteur unServeurWeb
: ServletEnregistrerPretSimpleFacade
: FacadeEnregistrerPretSimple 1. requête HTTP POST
2. doPost(HttpServletRequest, HttpServletResponse)
5. HttpServletResponse 6. réponse HTTP (document HTML)
3. insererPretEnCours(idUtilisateur,idExemplaire ) 4. date du prêt
Réutilisation des classes du client-serveur
27/02/22 © Robert Godin. Tous droits réservés. 44
<html>
<head>
<title>
Bibliothèque LeRat : Enregistrer un prêt (avec un servlet, interaction simplifiée)
</title>
</head>
<body>
<form action = "servlet/ServletEnregistrerPretsSimpleFacade" method = "post">
<p> Entrez l'identificateur de l'utilisateur et de l'exemplaire et cliquez Soumettre</p>
<table>
<tr>
<td>Identificateur d'utilisateur</td>
<td><input type = "text" name = "idUtilisateur" /></td>
</tr>
<tr>
<td>Identificateur d'exemplaire</td>
<td><input type = "text" name = "idExemplaire" /></td>
</tr>
</table>
<input type = "submit" value = "Soumettre" />
</form>
</body>
</html>
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.sql.*;
public class ServletEnregistrerPretsSimpleFacade extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
//Chercher le paramètre idUtilisateur de la FORM HTML et créer un Utilisateur String idUtilisateur = "";
try { idUtilisateur = request.getParameter("idUtilisateur"); } catch (Exception e) { e.printStackTrace(); }
//Chercher le paramètre idExemplaire de la FORM HTML et créer un Exemplaire String idExemplaire = "";
try { idExemplaire = request.getParameter("idExemplaire"); } catch (Exception e) { e.printStackTrace(); }
// Entête de la page de réponse HTML response.setContentType("text/html");
OutputStreamWriter unOutputStreamWriter =
new OutputStreamWriter(response.getOutputStream());
PrintWriter out = new PrintWriter(unOutputStreamWriter);
out.println("<html>");
out.println("<head><title>Réponse de ServletEnregistrerPretsSimpleFacadeEJB</title></head>");
out.println("<body>");
FacadeEnregistrerPretsSimple uneFacadeEnregistrerPretsSimple = null;
try{
uneFacadeEnregistrerPretsSimple = new FacadeEnregistrerPretsSimple();
// Enregistrer le prêt en passant par la façade java.sql.Date datePret =
27/02/22 © Robert Godin. Tous droits réservés. 46
15.2.3 Cycle de vie d'une servlet
Compilation et démarrage à la
première invocation (par conteneur)
– init() appelé une fois
permet d ’initialiser des ressources (e.g.
connexion)
– nouveau fil à chaque invocation d ’une méthode de service (doGet, doPost,…)
– destroy() à la fin
e.g. fermer connexion
15.2.4 Gestion d'une session HTTP dans une servlet
La FORM
n ’envoie que
le idUtilisateur
27/02/22 © Robert Godin. Tous droits réservés. 48
FormIdentificationUtilisateurFacade.html
<html>
<head>
<title> Exemple de session http pour cas Enregistrer Prêts : Identification utilisateur
</title>
</head>
<body>
<form action = "servlet/ServletIdentificationUtilisateurFacade" method = "post">
<p>Entrez l'identifiant de l'utilisateur et cliquez Soumettre</p>
<input type = "text" name = "idUtilisateur" />
<input type = "submit" value = "Soumettre" />
</form>
</body>
</html>
EnregistrerPrets en deux servlets
unFureteur unServeurWeb
: ServletIdentificationUtilisateurFacade
: ServletTerminerPretFacade uneSession :
HttpSession
uneFacadeEnregistrerPrets : FacadeEnregistrerPrets
uneTransaction 1. requête HTTP POST pour ServletIdentificationUtilisateurFacade
9. réponse HTTP (FormTerminerPret)
2. doPost(HttpServletRequest, HttpServletResponse)
8. HttpServletResponse
15. insererPretEnCours(idUtilisateur,idExemplaire ) 5. chercherOTDUtilisateurPrets()
4. «create»
3. «create»
6. setAttribute('uneFacadeEnregistrerPrets', uneFacadeEnregistrerPrets)
10. requête HTTP POST pour ServletTerminerPretFacade
11. doPost(HttpServletRequest, HttpServletResponse)
14. getStatutExem plaire() 12. getAttribute('uneFacadeEnregistrerPrets')
7. setAttribute('idUtilis ateur',idUtilis ateur)
13. getAttribute('idUtilisateur')
27/02/22 © Robert Godin. Tous droits réservés. 50
…
public class ServletIdentificationUtilisateurFacade extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//Chercher le paramètre idUtilisateur de la form String idUtilisateur = "";
try { idUtilisateur = request.getParameter("idUtilisateur"); } catch (Exception e) { e.printStackTrace(); }
// Créer un objet session si non existant
HttpSession uneSession = request.getSession(true);
// Entête de la page de réponse html response.setContentType("text/html");
…
try{
// Créer la facade et chercher l'OTDUtilisateurPrets
FacadeEnregistrerPrets uneFacadeEnregistrerPrets = new FacadeEnregistrerPrets();
OTDUtilisateurPrets unOTDUtilisateurPrets =
uneFacadeEnregistrerPrets.chercherOTDUtilisateurPrets(idUtilisateur);
// Affichage de l'idUtilisateur et du nombre de prêts out.println("Utilisateur :" + idUtilisateur);
out.println(" Nombre de prêts en cours :" + unOTDUtilisateurPrets.getNbPretsEnCours()+"<br>");
// Vérifier si les conditions préalables sont violées
…
}else{
// Sauvegarder les objets du contexte de la session
uneSession.setAttribute("uneFacadeEnregistrerPrets", uneFacadeEnregistrerPrets);
uneSession.setAttribute("idUtilisateur", idUtilisateur);
// Construire la FORM pour saisir l'idExemplaire
out.println("<form action = \"ServletTerminerPretFacade\" method = \"post\">");
out.println("<p>Entrez l'identifiant de l'exemplaire et cliquez Soumettre</p>");
out.println("<input type = \"text\" name = \"idExemplaire\" />");
out.println("<input type = \"submit\" value = \"Soumettre\" />");
out.println("</form>");
} ...
…
public class ServletTerminerPretFacade extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Chercher le paramètre idUtilisateur de la form String idExemplaire = "";
try { idExemplaire = request.getParameter("idExemplaire"); } catch (Exception e) { e.printStackTrace(); }
// Chercher l'objet de la session en cours
HttpSession uneSession = request.getSession(false);
// Chercher les objets du contexte de la session en cours FacadeEnregistrerPrets uneFacadeEnregistrerPrets =
(FacadeEnregistrerPrets)uneSession.getAttribute("uneFacadeEnregistrerPrets");
String idUtilisateur = (String)uneSession.getAttribute("idUtilisateur");
// Entête de la page de réponse html
…
try{
// Vérifier statut de l'exemplaire
String statut = uneFacadeEnregistrerPrets.getStatutExemplaire(idExemplaire);
if (statut.equals("disponible")){
// Enregistrer le prêt en passant par la façade java.sql.Date datePret =
uneFacadeEnregistrerPrets.insererPretEnCours();
…
finally{
try{
out.println("</body></html>");
out.close();
uneFacadeEnregistrerPrets.confirmerTransaction();
}
27/02/22 © Robert Godin. Tous droits réservés. 52
15.2.5 DataSource,
ConnectionPoolDataSource et PooledConnection
Passage par serveur JNDI (Java Naming and Directory Interface)
– e.g. service d’annuaire LDAP
– repérage de ressources (e.g. serveur BD)
– accès sécurisé
Ouverture d ’une Connection en passant par DataSource
package ExemplesJDBC.GererPrets;
import java.sql.*;
import javax.naming.*;
import javax.sql.*;
public class UsineConnection { public UsineConnection() {}
…
public Connection getConnectionFromDataSource(
String nomDataSource) throws Exception {
InitialContext unContexte = new InitialContext();
DataSource unDataSource =
(DataSource)unContexte.lookup(nomDataSource);
Connection uneConnection = unDataSource.getConnection();
return uneConnection;
}
}
27/02/22 © Robert Godin. Tous droits réservés. 54
Enregistrement du DataSource par descripteur de
déploiement XML pour serveur embarqué OC4J de Oracle9i JDevelopper (généré par JDevelopper)
Connection uneConnection =
uneUsineConnection.getConnectionFromDataSource("jdbc/ora9icleratCoreDS");
<?xml version = '1.0' encoding = 'windows-1252'?>
<!DOCTYPE data-sources PUBLIC "Orion data-sources" "http://xmlns.oracle.com/ias/dtds/data-sources.dtd">
<data-sources>
<data-source class="com.evermind.sql.DriverManagerDataSource"
connection-driver="oracle.jdbc.driver.OracleDriver"
ejb-location="jdbc/ora9icleratDS"
inactivity-timeout="30"
location="jdbc/ora9icleratCoreDS"
name="ora9icleratDS"
password="oracle"
pooled-location="jdbc/ora9icleratPooledDS" url="jdbc:oracle:thin:@localhost:1521:ora9i"
username="clerat"
xa-location="jdbc/xa/ora9icleratXADS"/>
</data-sources>
Partage d'un pool de connexions
package ExemplesJDBC.GererPrets;
import java.sql.*;
import javax.naming.*;
import javax.sql.*;
import oracle.jdbc.pool.*;
public class UsineConnection { public UsineConnection() {}
…
public Connection getConnectionFromConnectionPoolDataSource(
String nomDataSource) throws Exception {
InitialContext unContexte = new InitialContext();
ConnectionPoolDataSource unDataSource =
(ConnectionPoolDataSource)unContexte.lookup(nomDataSource);
PooledConnection unePooledConnection = unDataSource.getPooledConnection();
Connection uneConnection = unePooledConnection.getConnection();
return uneConnection;
}
}
27/02/22 © Robert Godin. Tous droits réservés. 56
15.2.6 Mécanismes de sécurité pour l'accès à un servlet
Sécurité programmatique
Sécurité déclarative par le conteneur
– rôles/utilisateurs
– géré par conteneur
15.3 Architecture pour la persistance transparente
Persistance gérée par la classe métier
Transparent au client
Mécanisme paresseux de
matérialisation/dématérialisation
– gestion de cache transactionnelle
– programmation complexe
Norme Java Data Objects (JDO)
– http://access1.sun.com/jdo/
– inspirée de ODMG
– outils : http://www.javaskyline.com/database.html
Nouvelle norme Java Persistence API (JPA)
27/02/22 © Robert Godin. Tous droits réservés. 58
15.4 Norme EJB de J2EE (
http://java.sun.com/products/ejb/)
Transparence « extrême »
– persistance
– répartition
– services
Spécification déclarative de services
– comportement transactionnel
– sécurité
– gestion de ressources (CPU, mémoire, serveurs, ...)
e.g. partage transparent d’un bassin d’objets EJB (pooling) entre clients
robustesse, « scalabilité »
Prise en charge des services par le conteneur à EJB
Séparation propre des responsabilités (rôles)
Fournisseur de EJB (EnterpriseBean Provider)
– développe les composantes EJB
Assembleur d'application (Application Assembler) .
– assemble EJB + servlet, JSP, HTML, etc.
Déployeur (Deployer)
– déploie les EJB dans leur environnement d'exécution
Fournisseur de serveur EJB (EJB Server Provider).
– serveur EJB : services de bas niveau pour le conteneur EJB
Fournisseur de conteneur EJB (EJB Container Provider)
– conteneur EJB : environnement de déploiement et d'exécution des EJB
Administrateur de Système (System Administrator)
27/02/22 © Robert Godin. Tous droits réservés. 60
Catégories de EJB
EJB session (Session Bean)
– service d ’objet distant
– un seul client à la fois par objet
– partage d’un bassin d’objets entre clients
– état au besoin entre les appels
stateful/stateless session EJB
– non persistent (perdu suite à une panne)
EJB entité (Entity Bean)
– services d'objet distant persistant
– objet ~ proxy pour une ligne d'une table
– un objet EJB entité peut être partagé par plusieurs clients
EJB message (Message Bean)
– service de message
Codage d ’un EJB
Interface home
– usine à objet EJB
Interface à distance (remote)
– accès aux méthodes d'un objet EJB
Classe bean (bean class)
– implémente les méthodes de
l'objet EJB
27/02/22 © Robert Godin. Tous droits réservés. 62
15.4.1 Développement d'un EJB session sans état : FacadeEnrPretSimpleSessionEJB
Interface home (usine à EJB)
Interface remote (interface à l’objet EJB)
package ExemplesJDBC.GererPrets;
import javax.ejb.EJBHome;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
public interface FacadeEnrPretSimpleSessionEJBHome extends EJBHome {
FacadeEnrPretSimpleSessionEJB create() throws RemoteException, CreateException;
}
NB Paramètres sérialisables (au sens de Java) passés par valeur
package ExemplesJDBC.GererPrets.impl;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import java.sql.Date;
import ExemplesJDBC.GererPrets.*;
import java.sql.Connection;
import java.util.*;
public class FacadeEnrPretSimpleSessionEJBBean implements SessionBean {
public void ejbCreate(){}
public void ejbActivate(){}
public void ejbPassivate(){}
public void ejbRemove(){}
public void setSessionContext(SessionContext ctx){}
public Date insererPretEnCours(String idUtilisateur, String idExemplaire) throws Exception {
UsineConnection uneUsineConnection = new UsineConnection();
Connection uneConnection =
uneUsineConnection.getConnectionFromDataSource("jdbc/ora9icleratCoreDS");
Utilisateur unUtilisateur = new Utilisateur(idUtilisateur);
Exemplaire unExemplaire = new Exemplaire(idExemplaire);
// Générer la date du jour et l'objet PrêtEnCours
Calendar maintenant = Calendar.getInstance(); // Calendrier avec date actuelle java.sql.Date dateMaintenant = new java.sql.Date(maintenant.getTime().getTime());
PrêtEnCours leNouveauPrêtEnCours =
new PrêtEnCours(unUtilisateur,dateMaintenant,unExemplaire);
// Matérialiser le PrêtEnCours dans la BD CourtierBDPrêtEnCours unCourtierBDPrêtEnCours = new CourtierBDPrêtEnCours(uneConnection);
unCourtierBDPrêtEnCours.insérerPrêtEnCours(leNouveauPrêtEnCours);
27/02/22 © Robert Godin. Tous droits réservés. 64
Descripteur de
déploiement XML
<?xml version = '1.0' encoding = 'windows-1252'?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN"
"http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">
<ejb-jar>
<enterprise-beans>
<session>
<description>Session Bean ( Stateless )</description>
<display-name>FacadeEnrPretSimpleSessionEJB</display-name>
<ejb-name>FacadeEnrPretSimpleSessionEJB</ejb-name>
<home>ExemplesJDBC.GererPrets.FacadeEnrPretSimpleSessionEJBHome</home>
<remote>ExemplesJDBC.GererPrets.FacadeEnrPretSimpleSessionEJB</remote>
<ejb-class>ExemplesJDBC.GererPrets.impl.FacadeEnrPretSimpleSessionEJBBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Bean</transaction-type>
</session>
</ejb-jar>
Client du EJB : façade locale qui délègue à la façade EJB distante
(patron Business Delegate)
package ExemplesJDBC.GererPrets;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import ExemplesJDBC.GererPrets.FacadeEnrPretSimpleSessionEJB;
import ExemplesJDBC.GererPrets.FacadeEnrPretSimpleSessionEJBHome;
// Façade pour le cas d'utilisation EnregistrerPretsSimple
// La façade utilise les services du EJB session FacadeEnrPretSimpleSessionEJB public class FacadeEJBEnregistrerPretsSimple
{
public FacadeEJBEnregistrerPretsSimple()throws Exception {
}
// Insère le prêt et retourne la date d'enregistrement public java.sql.Date insererPretEnCours(
String idUtilisateur, String idExemplaire) throws Exception{
// Chercher une référence au EJB session
FacadeEnrPretSimpleSessionEJB uneFacadeEnrPretSimpleSessionEJB;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.evermind.server.rmi.RMIInitialContextFactory");
env.put(Context.SECURITY_PRINCIPAL, "admin");
env.put(Context.SECURITY_CREDENTIALS, "welcome");
env.put(Context.PROVIDER_URL, "ormi://localhost:23893/current-workspace-app");
Context ctx = new InitialContext(env);
FacadeEnrPretSimpleSessionEJBHome facadeEnrPretSimpleSessionEJBHome =
27/02/22 © Robert Godin. Tous droits réservés. 66
JDevelopper 10g (déploiement
de défaut différent)
Interposition transparente d ’objets
: Controle Enregi strerPretsSimpleAvecFacadeEJB
: FacadeEJBEnregistrerPretsSimple
ctx : Context
uneFacad eEnrPretSim ple SessionEJB : FacadeEnregistrerPretsSimpleSessionEJB
: FacadeEn regi strerPretsSimpleSessi onEJBBean facadeEnrPretSimpl
eSessionEJBHome
In terposition transparente d'objets générés par le conten eur pour e ffectuer l'envoie de message à l'objet be an Client du EJB
ObjetEJB local qui implémente l'interface remote
Conteneur EJB Poste du client du EJB
1. insererPretEnCours(idUtilisateur,idExemplaire)
7. in sererPretEnCours(idUtil is ateur,idExemplaire)
8. insererPretEnCours(idUtilisateur,idExemplaire) 2. «create»
3. lookup()
4. facadeEnrPretSimpleSessionEJBHome 5. create()
6. uneFacadeEnrPretSimpleSessionEJB Ob jet home
Objet bean
Conteneur
de bean
27/02/22 © Robert Godin. Tous droits réservés. 68
Dans ServletEnregistrerPretsSimpleFacade remplacer FacadeEnregistrerPretsSimple par une
FacadeEJBEnregitrerPretSimple
package ExemplesJDBC.GererPrets;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.sql.*;
public class ServletEnregistrerPretsSimpleFacadeEJB extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
…
FacadeEJBEnregistrerPretsSimple uneFacadeEnregistrerPretsSimple = null;
try{
uneFacadeEnregistrerPretsSimple = new FacadeEJBEnregistrerPretsSimple();
…
}
}
15.4.2 Développement d'un EJB session avec état
package ExemplesJDBC.GererPrets;
import javax.ejb.EJBHome;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
public interface FacadeEnrPretsSessionEJBHome extends EJBHome {
FacadeEnrPretsSessionEJB create() throws RemoteException, CreateException;
}
package ExemplesJDBC.GererPrets;
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
import java.sql.Date;
public interface FacadeEnrPretsSessionEJB extends EJBObject {
OTDUtilisateurPrets chercherOTDUtilisateurPrets(String idUtilisateur) throws Exception, RemoteException;
void confirmerTransaction() throws Exception, RemoteException;
27/02/22 © Robert Godin. Tous droits réservés. 70
Classe bean
package ExemplesJDBC.GererPrets.impl;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import java.sql.Connection;
import ExemplesJDBC.GererPrets.*;
import java.sql.Date;
import java.util.*;
public class FacadeEnrPretsSessionEJBBean implements SessionBean {
private Connection uneConnection;
private Utilisateur unUtilisateur;
private Exemplaire unExemplaire;
private CourtierBDPrêtEnCours unCourtierBDPretEnCours;
public void ejbCreate()throws Exception{}
public void ejbActivate(){}
public void ejbPassivate(){}
public void ejbRemove(){}
public void setSessionContext(SessionContext ctx) { try {
UsineConnection uneUsineConnection = new UsineConnection();
uneConnection =
uneUsineConnection.getConnectionFromDataSourceSansAutoCommit("jdbc/ora9icleratCoreDS");
}
catch(Exception lException){
lException.printStackTrace();
} }
…
État maintenu entre les appels Méthode du cycle de vie appelée à la création de l’objet avant ejbCreate()
NB setSessionContext() permet
d’initialiser la connexion au
DataSource (interdit dans
ejbCreate()…)
Classe Bean (suite) : méthode métier identique à FacadeEnregistrerPrets
public OTDUtilisateurPrets chercherOTDUtilisateurPrets(String idUtilisateur) throws Exception { // Création du courtier et dématérialisation de l'Utilisateur
CourtierBDUtilisateur unCourtierBDUtilisateur = new CourtierBDUtilisateur(uneConnection);
unUtilisateur =
unCourtierBDUtilisateur.chercherUtilisateurParIdUtilisateur(idUtilisateur);
//Création du courtier et dématérialisation des PrêtsEnCours
unCourtierBDPretEnCours = new CourtierBDPrêtEnCours(uneConnection);
unCourtierBDPretEnCours.chercherLesPrêtsEnCours(unUtilisateur);
// Retourner l'objet de transfert de données OTDUtilisateurPrets if (unUtilisateur instanceof Membre){
unCourtierBDUtilisateur.chercherVariablesStatiquesDeMembre();
Membre unMembre = (Membre)unUtilisateur;
return new OTDUtilisateurPrets(
unMembre.getCatégorie(),
unMembre.conditionsPrêtAcceptées(), unMembre.getNbPrêtsEnCours(),
Membre.getNbMaxPrêts(), unMembre.getNbRetards());
} else {
return new OTDUtilisateurPrets(
unUtilisateur.getCatégorie(),true,unUtilisateur.getNbPrêtsEnCours(),0,0);
27/02/22 © Robert Godin. Tous droits réservés. 72
Processus de création d ’un EJB avec état
unClientEJB unEJBHome unObjetEJBl oca l u nSessio nContext unObjetEJBBean 1. create()
2. «create»
3. «create»
4. «create»
5. setSessionContext()
6. ejbCreate()
Client du EJB : façade locale qui délègue à la façade EJB distante
…
public class FacadeEJBEnregistrerPrets {
private FacadeEnrPretsSessionEJB uneFacadeEnrPretsSessionEJB;
public FacadeEJBEnregistrerPrets()throws Exception {
// Le constructeur crée l'objet session EJB façade Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.evermind.server.rmi.RMIInitialContextFactory");
env.put(Context.SECURITY_PRINCIPAL, "admin");
env.put(Context.SECURITY_CREDENTIALS, "welcome");
env.put(Context.PROVIDER_URL, "ormi://localhost:23893/current-workspace-app");
Context ctx = new InitialContext(env);
FacadeEnrPretsSessionEJBHome facadeEnrPretsSessionEJBHome =
(FacadeEnrPretsSessionEJBHome)ctx.lookup("FacadeEnrPretsSessionEJB");
uneFacadeEnrPretsSessionEJB = facadeEnrPretsSessionEJBHome.create( ); } // Cherche un Utilisateur avec ses PretsEnCours et retourne
// les données nécessaires pour EnregistrerPrets (OTDUtilisateurPrets) // Une exception est levée si l'Utilisateur n'existe pas
public OTDUtilisateurPrets chercherOTDUtilisateurPrets(String idUtilisateur)throws Exception { return uneFacadeEnrPretsSessionEJB.
chercherOTDUtilisateurPrets(idUtilisateur);
27/02/22 © Robert Godin. Tous droits réservés. 74
Dans ServletIdentificationUtilisateurFacade et ServletTerminerPretFacade
remplacer FacadeEnregistrerPrets par une FacadeEJBEnregistrerPrets
package ExemplesJDBC.GererPrets;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.sql.*;
public class ServletIdentUtilFacadeEJB extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
…
try{
// Créer la facade et chercher l'OTDUtilisateurPrets
FacadeEJBEnregistrerPrets uneFacadeEnregistrerPrets = new FacadeEJBEnregistrerPrets();
OTDUtilisateurPrets unOTDUtilisateurPrets =
uneFacadeEnregistrerPrets.chercherOTDUtilisateurPrets(idUtilisateur);
…
15.4.3 Support de
transactions distribuées
Plusieurs ressources indépendantes
– serveur BD, serveur JMS, ...
Protocole transparent de transaction répartie
Démarcation programmatique ou
déclarative
27/02/22 © Robert Godin. Tous droits réservés. 76
15.4.4 Démarcation programmatique de transaction distribuée (bean managed transaction demarcation)
CREATE TABLE Compte
(noCompte INTEGER PRIMARY KEY,
solde DECIMAL(10,2) CHECK (solde >= 0), dateOuverture DATE,
noClient)
package mypackage1;
import javax.ejb.*;
import java.rmi.RemoteException;
import java.sql.Connection;
public interface BanqueSessionBMTDEJB extends EJBObject {
void transferer(int noCompteADebiter, int noCompteACrediter, double montant) throws RemoteException, EJBException;
}
Deux connexions
indépendantes !
Classe bean
…
// Exemple de EJB session qui réalise une transaction répartie
// Démarcation programmatique de transaction avec javax.transation.UserTransaction public class BanqueSessionBMTDEJBBean implements SessionBean {
private SessionContext sessionContext;
private Connection connectionBanqueDebit;
private Connection connectionBanqueCredit;
… public void setSessionContext(SessionContext ctx){
sessionContext = ctx;
ouvrirConnections();
}
void ouvrirConnections() throws EJBException { try{
UsineConnection uneUsineConnection = new UsineConnection();
connectionBanqueDebit =
uneUsineConnection.getConnectionFromDataSource("jdbc/ora9igodinCoreDS");
connectionBanqueCredit =
uneUsineConnection.getConnectionFromDataSource("jdbc/ora9igodin2CoreDS");
}
catch(Exception lException){
throw new EJBException(lException);