Serialisation
La sérialisation est un procédé introduit dans le JDK version 1.1 qui permet de
rendre un objet persistant. Cet objet est mis sous une forme sous laquelle il pourra
être reconstitué à l'identique. Ainsi il pourra être stocké sur un disque dur ou
transmis au travers d'un réseau pour le créer dans une autre JVM. C'est le procédé
qui est utilisé par RMI. La sérialisation est aussi utilisée par les beans pour
sauvegarder leurs états.
Au travers de ce mécanisme, Java fourni une façon facile, transparente et standard
de réaliser cette opération : ceci permet de facilement mettre en place un
mécanisme de persistance. Il est de ce fait inutile de créer un format particulier
pour sauvegarder et relire un objet. Le format utilisé est indépendant du système
d'exploitation. Ainsi, un objet sérialisé sur un système peut être réutilisé par un
autre système pour récréer l'objet.
L'ajout d'un attribut à l'objet est automatiquement pris en compte lors de la
sérialisation. Attention toutefois, la déserialisation de l'objet doit se faire avec la
classe qui a été utilisée pour la sérialisation.
La sérialisation peut s'appliquer facilement à tous les objets.
Cliquez sur l'icône pour ajouter une image
Introduction aux JFC/Swing
Qu’est ce que les JFC?
JFC Java Foundation Classes
5 parties :
Java 1.1 Abstract Window Toolkit (AWT)
Java2D API
***Swing***
Native Drag and Drop, et Copy and Paste
API pour l'Accessibilité (aveugle, ...)
Qu’est-ce que Swing?
Abstract Window Toolkit (AWT) V2
100% Pure Java
Nécessite le JDK 1.1.2 ou supérieur
Fait parti des JFC
Composants
Nouveaux composants de haut niveau
Look & Feel modulable
Philosophie Swing
Une directive de conception fondamentale est
«rendre les choses simples faciles, et les choses
difficiles possibles»
Ensemble plus Riche de Composants
Remplace l’AWT
Ajoute des composants plus complexes
Composants Swing sont basés sur Java
Si des problèmes, les même problèmes partout
100% Pure Java
Java 1.1.2+ nécessaire
Uniquement le modèle d'événements de Java 1.1
Les Particularités de Swing
Inclut avec les API Java 2 (JDK 1.2)
Utilisable dans les Environnements Java 1.1
javax.swing.*
Ne peut être dans la hiérarchie java.* et être
téléchargé par des browsers JDK 1.1
Deux Vues des Swing
Alternative aux composants AWT Java 1.1
modèle d’événements 1.0 NON supporté
Quelques nouveaux composants.
Interface Model/View/Controller
Séparer les données des vues écrans et des interactions
Plus de travail nécessaire
Les classes Swing
L’ensemble des composants Swing
Exemple de programme basé sur les Swing
De l’AWT aux SWING
Pour la plupart des composants, ajouter J avant le
nom
Button JButton, Applet JApplet, …
Modèle d'événements Java 1.1
Les containers Swing intègrent le double-buffer
Evite le scintillement des composants Swing
Le Look and Feel
Swing propose plusieurs aspects et utilisation de
l’interface graphique : Look and Feel (L&F).
Le Look and Feel de Java est appelé Metal ou Java
L&F : c’est le L&F par défaut. On peut aussi avoir
les L&F Motif, Windows et Macintosh (contrôlé
par des droits) et même se créer son propre L&F.
Le Look and Feel
On peut connaître les divers L&F utilisables sur
une machine à l’aide de la méthode statique
UIManager.getInstalledLookAndFeels(); qui
retourne un tableau de
UIManager.LookAndFeelInfo
Le Look and Feel
Les différents L&F de la plate-forme Windows
Le Look and Feel
Personnaliser l ’aspect des composants
graphiques :
indépendant des plate-formes : style Metal
dépendant du système :windows, ...
Le Look and Feel
Le Look and Feel
Utiliser le look d ’affichage Metal
try {
UIManager.setLookAndFeel (
"javax.swing.plaf.metal.MetalLookAndFeel");
} catch (java.lang.ClassNotFoundException e)
{ // Ne peut changer le look and feel
}
Ou
try {
UIManager.setLookAndFeel (
UIManager.getCrossPlatformLookAndFeelClassName());
} catch (java.lang.ClassNotFoundException e)
{ // Ne peut changer le look and feel
}
Le Look and Feel
Utiliser le look d ’affichage du système
try {
UIManager.setLookAndFeel (
UIManager.getSystemLookAndFeelClassName());
} catch (java.lang.ClassNotFoundException e)
{ // Ne peut changer le look and feel
}
Swing vs. AWT 1.1
class MyActionListener implements ActionListener {
public void actionPerformed (ActionEvent e) {
System.out.println (e.getActionCommand());
}
}
...
ActionListener al = new MyActionListener();
Button b1 = new Button ("Hello");
b1.addActionListener (al);
add (b1, BorderLayout.NORTH);
JButton b2 = new JButton ("World");
b2.addActionListener (al);
add (b2, BorderLayout.SOUTH);
Le modèle MVC
Swing utilise fondamentalement une architecture
d’interface homme-machine inspiré de Smalltalk :
l’architecture Model-View-Controller.
Cette architecture est composée de trois parties :
le modèle qui est la partie décrivant les données à
afficher
la vue qui est la représentation graphique de ces
données
le contrôleur qui est la partie qui traite des interactions
du composant avec l’utilisateur.
Le modèle MVC
Intérêts de l’architecture MVC
meilleure modularité
possibilité d’associer plusieurs vues distinctes à un
même modèle (histogramme, courbes, camembert,
valeur flottante, ...)
possibilité de changer l’implémentation d’un
modèle (optimisation, réorganisation, ...) sans rien
changer aux vues et aux contrôleurs.
Vue des paquetages Swing
La collection Swing est constitué de 17
paquetages
javax.swing
le paquetage Swing racine définit les
composants, les adapters, les modèles par
défaut des composants, et les interfaces pour
tous les modèles et les containers.
Vue des paquetages Swing
javax.swing.border
Le paquetage border déclare l ’interface Border et ses
classes, afin de définir les styles d ’affichage
spécifiques aux bords des composants.
javax.swing.colorchooser
Le paquetage colorchooser contient les classes pour
choisir la couleur du composant.
Vue des paquetages Swing
javax.swing.event
Le paquetage event est pour les types d ’événements et
les listeners spécifiques des composants Swing. En
plus des types java.awt.event, les composants Swing
peuvent générer leurs propres types d ’événements.
javax.swing.filechooser
le paquetage filechooser contient les classes pour la
sélection de fichiers.
Vue des paquetages Swing
javax.swing.plaf.*
Le paquetage look-and-feel (Pluggable Look And Feel)
contient les classes (delegates) de l ’Interface
Utilisateur (UI) qui implémentent les aspects des
composants Swing. javax.swing.table
Le paquetage table définit les interfaces et les classes
pour les tableaux.
Vue des paquetages Swing
javax.swing.text
Le paquetage text contient les classes pour le
framework des documents Swing.
javax.swing.text.html.*
Le paquetage text.html contient les classes pour
l ’analyse et l ’affichage de l ’HTML version 3.2.
Vue des paquetages Swing
javax.swing.text.rtf
Le paquetage text.rtf définit les classes pour le
rendu de documents basic Rich Text Format
(RTF).
javax.swing.tree
Le paquetage tree contient les interfaces et les
classes qui supportent l ’affichage sous forme
d ’arbres (explorateur Window).
Vue des paquetages Swing
javax.swing.undo
Le paquetage undo permet le support des
classes pour implémenter les capacités du
undo/redo dans une GUI.
javax.accessibility
Le paquetage JFC Accessibility est inclu avec
les classes Swing, pour le support d ’outils
d ’aide aux personnes handicapées.
Hiérarchie Swing
Hiérarchie Swing
Composants de haut niveau
Toutes les sous-classes de Window, non de
JComponent
Non portables, ils ont des composants peer
Composants ajoutés au panel de contenu
interface RootPaneContainer - délégué au container
Utilisation du RootPaneContainer
Ne pas ajouter de composants directement dans les
containers de haut niveau :
aFrame.add (new Button (“Help”));
Ajouter au panel de contenu:“content pane”
aJFrame.getContentPane().add (…);
possède un Layout manager - par défaut: BorderLayout
JDialog, JFrame, JWindow, JApplet, JInternalFrame
Exemple de JFrame
public class FrameTester {
public static void main (String args[]) {
JFrame f = new JFrame ("JFrame Example");
Container c = f.getContentPane();
c.setLayout (new FlowLayout());
for (int i = 0; i < 5; i++) {
c.add (new JButton ("No"));
c.add (new Button ("Batter"));
}
c.add (new JLabel ("Swing"));
f.setSize (300, 200);
f.show();
}
}
Une directive de conception fondamentale est «
rendre les choses simples faciles, et les choses
difficiles possibles ».
multithreading
PLAN
Introduction
Définition
Raison d’être
Création de Thread
Par implémentation
Par héritage
Gestion de Thread
Méthodes de gestion
Diagrammes d’état
Qu’est-ce qu’un Thread?
Un ordinateur qui exécute un programme :
Possède un CPU
Stocke le programme à exécuter
Possède une mémoire manipulée par le programme
Multitasking géré par l’OS
Un thread (« file ») a ces mêmes capacités
A accès au CPU
Gère un processus
A accès à la mémoire, qu’il partage avec d’autres files
Multithreading géré par la JVM
Definition
Une thread (appelée aussi processus léger ou activité)
est une suite d'instructions à l'intérieur d'un process.
Les programmes qui utilisent plusieurs threads sont
dits multithreadés.
Les threads peuvent être créés comme instance d'une
classe dérivée de la classe Thread. Elles sont lancées
par la méthode start(), qui demande à l'ordonanceur de
thread de lancer la méthode run() de la thread. Cette
méthode run() doit être implantée dans le programme.
Notion de threads
Un processus multi-threads
Un processus avec
un seul thread Thread 1 Thread 2 Thread 3
Il faut voir une processus comme le code correspondant au programme.
Le thread est l'entité qui exécute le code.
Toute application comporte au moins un thread appelé
« thread pincipal ».
Pourquoi le multithreading?
Un programme moderne est composé de
Une interface graphique
Quelques composantes pouvant agir de manière autonome
Sans multithreading
Les composantes ne pourraient agir que lorsque l’interface est
suspendue
Plus généralement, le multithreading
Permet de réaliser plusieurs processus indépendants en parallèle
Permet de gérer les files d’attente
Permet au besoin de synchroniser les différents processus entre eux
Exemple
class DeuxThreadAsynchrones {
public static void main(String args[ ]) {
new UneThread("la thread 1").start();
new UneThread("la seconde thread").start();
}
}
class UneThread extends Thread {
public UneThread(String str) {
super(str);
}
public void run() {
for (int i=0; i<10; i++) {
System.out.println(i+" "+getName());
try {sleep((int)(Math.random()*10));}
catch (InterruptedException e){}
}
System.out.println(getName()+" est finie");
}
}
Création de Thread
Par implémentation de l’interface Runnable
Usage
public void MaClasse implements Runnable
Avantages et inconvénients
Meilleur sur le plan orienté objet
La classe peut hériter d’une autre classe
Consistance
Par héritage de la classe Thread elle-même
Usage
public void MaClasse extends Thread
Avantages et inconvénients
Code simple (l’objet est un Thread lui-même)
La classe ne peut plus hériter d’une autre classe
Quelle solution choisir ?
Sous-classer Thread
Lorsqu’on désire paralléliser une classe qui n’hérite pas déjà
d’une autre classe
Implémenter Runnable
Lorsque la super classe est imposée (exemple : une applet
que l’on désire paralléliser),
Ou lorsqu’un partage de contexte est requis par un nombre
quelconque de threads
En général, le démarrage du ou des threads associés à
l’objet est effectué par l’objet lui-même
(new Thread(this)).start();
Création de Thread
public class MaFile implements Runnable {
public void run(){
byte[] buffer=new byte[512];
int i=0;
while(true){
if(i++%10==0)System.out.println(""+i+" est divisible par 10");
if (i>101) break;
}
}
}
public class LanceFile {
public static void main(String[]arg){
Thread t=new Thread(new MaFile());
t.start(); Le constructeur de la classe Thread
} attend un objet Runnable
}
en argument
Création de Thread
public class MyThread extends Thread {
public void run(){
byte[] buffer=new byte[512];
int i=0;
while(true){
if(i++%10==0) System.out.println(""+i+" est divisible par 10");
if(i>101) break;
}
}
}
public class LaunchThread{
public static void main(String[]arg){
MyThread t=new MyThread(); Grâce à l’héritage, un objet de type
t.start(); MyThread est lui-même Runnable,
} on peut donc appeler un constructeur
} sans argument
Gestion des Thread
t.start()
Appeler cette méthode place le thread dans l’état “runnable”
Eligible par le CPU
t.yield() throws InterruptedException
La VM arrête la file active et la place dans un ensemble de files activables.
(runnable state)
La VM prend une file activable et la place dans l’état actif (running state)
t.sleep(int millis) throws InterruptedException
La VM bloque la file pour un temps spécifié (état « d’attente »)
t.join() throws InterruptedException
Met la file en attente jusqu’au moment où la file t est terminée
(a fini sa méthode run()). Le thread appelant redevient alors activable.
Gestion des Thread
Thread.yield() throws InterruptedException
La VM arrête la file active et la place dans un ensemble de files activables.
(runnable state)
La VM prend une file activable et la place dans l’état actif (running state)
t.sleep(int millis) throws InterruptedException
La VM bloque la file pour un temps spécifié (état « d’ attente »)
t.join() throws InterruptedException
Met la file en attente jusqu’au moment où la file t est terminé (a fini sa
méthode run()). Le thread appelant redevient alors activable.
t.currentThread() throws InterruptedException
Donne le thread actuellement en cours d'exécution
Autre opérations d'un thread
Pour arrêter un thread on utilise l'opération « stop » :
public final void stop();
Pour connaître la priorité d'un thread, on emploi la méthode
« getPriority » :
public final int getPriority();
De plus, pour fixer la priorité d'un thread, on utilise « setPriority » :
public final void setPriority(int newPriority);
Gestion des Thread
Diagrammes d’état
Object.notify()
t.sleep()
Object.notifyAll()
En attente
début fin
Object.wait()
Fin du sleep()
t.yield()
t.start()
Activable Active
Scheduler Fin de run()
Ensemble de files éligibles Une des files éligibles, pas
nécessairement celle avec la plus
grande priorité.
Comment récupérer le thread courant ?
Lorsqu'une méthode est exécutée, elle peut l'être par plusieurs
threads.
Pour connaître le thread courant, elle peut utiliser l'opération
« currentThread » :
public static Thread currentThread();
A partir de la référence vers le thread récupéré, on peut appliquer
toutes les opérations traditionnelles aux threads.
L'opération « currentThread » peut être également
utilisée pour récupérer le thread principal.
Exemple
// utilisation de threads
import java.io.*;
import java.util.*;
public class thread2{
public static void main(String[] arg) {
// init thread courant
Thread main=Thread.currentThread();
// on donne un nom au thread courant
main.setName("myMainThread");
// début de main
System.out.println("début du thread " +main.getName());
// création de threads d'exécution
Thread[] tâches=new Thread[5];
for(int i=0;i<tâches.length;i++){
// on crée le thread i
Exemple
tâches[i]=new Thread() {
public void run() {
affiche();
}
};//déf tâches[i]
// on fixe le nom du thread
tâches[i].setName(""+i);
// on lance l'exécution du thread i
tâches[i].start();
}//for
// fin de main
System.out.println("fin du thread " +main.getName());
}//Main
public static void affiche() {
// on récupère l'heure
Calendar calendrier=Calendar.getInstance();
String H=calendrier.get(Calendar.HOUR_OF_DAY)+":"
+calendrier.get(Calendar.MINUTE)+":"
+calendrier.get(Calendar.SECOND);
// affichage début d'exécution
System.out.println("Début d'exécution de la méthode affiche dans le Thread " +
Thread.currentThread().getName()+ " : " + H);
Exemple
// mise en sommeil pendant 1 s
try{
Thread.sleep(1000);
}catch (Exception ex){}
// on récupère l'heure
calendrier=Calendar.getInstance();
H=calendrier.get(Calendar.HOUR_OF_DAY)+":"
+calendrier.get(Calendar.MINUTE)+":"
+calendrier.get(Calendar.SECOND);
// affichage fin d'exécution
System.out.println("Fin d'exécution de la méthode affiche dans le Thread "
+Thread.currentThread().getName()+ " : " + H);
}// affiche
}//classe
Priorités
Principes
Java offre la possibilité de fixer les priorités des dif-férents threads d’un
processus.
Niveaux de priorités absolus (gestion simplifiée).
Seuls les threads à l’état actif s’exécutent et peu-vent partager le CPU.
Le partage de temps entre threads d’une même priorité dépend de l’OS.
Les threads actifs de plus hautes priorité se parta-gent le CPU (si l’OS le
permet).
Méthodes
void setPriority(int) modifie la priorité du receveur. Le paramètre appartient à
l’intévalle [MIN_PRIORITY, MAX_PRIORITY]. Dans le cas contraire
IllegalArgumentException est levée.
int getPriority() permet de connaître la priorité d’un thread.
Le niveau de priorité “normal” est donné par la constante NORM_PRIORITY.
Accès concurrents
Que se passe t'il si plusieurs threads accèdent à la même méthode ou à la même
ressource au même instant ?
Comportement imprévisible selon les applications
problématique des accès concurrents
Pour qu'une méthode ne soit pas utilisée par plus d'un thread à la fois, il faut la
spécifier « synchronized » :
synchronized type_de_retour nom_methode ( liste des paramètres )
Un même thread pourra tout de même appeler
récursivement cette opération.
Les verrous
Un verrou ( en anglais « mutex » ) est un concept qui lorsqu'il est activé
empêche les threads qui n'ont pas activés le verrou d'utiliser le code
verrouillé.
Tant que le verrou n'est pas levé, seul un thread peut être actif dans le code
verrouillé.
Chaque objet java peut servir de verrou.
Comment créer une zone verrouillée ?
On applique « synchronized » sur un objet.
Synchronisation
Certains accès simultanés à une ressource peuvent être
gênants.
Gérer les concurrences d’accés à une méthode
Cela se fait en déclarant la méthode synchronized
public synchronized void maMethode() {
...
}
Lorsqu’un thread exécute cette méthode sur un objet, un
autre thread ne peut pas l’exécuter pour le même objet.
En revanche, il peut exécuter cette méthode pour un autre
objet.
Contrôler l’accés à un objet
Déclarer l’objet synchronized
public void maMethode() {
...
synchronized(objet) {
objet.methode();
}
...
}
L’accès à l’objet passé en paramètre de synchronized(Object obj)
est réservé à un thread et un seul.
Pour éviter une dégradation des performances il faut que les
sections critiques soient courtes et utilisées à bon escient.
Thread en tâche de fond (démon)
Il existe une catégorie de threads qualifiés de
démons : leur exécution peut se poursuivre même
après l‘arrêt de l'application qui les a lancés.
Le thread doit d'abord être créé comme thread
standard puis transformé en demon par un appel à
la méthode setDaemon() avec le paramètre true.
Cet appel se fait avant le lancement du thread,
sinon une exception de type
IllegalThreadStateException est levée.
Groupes de threads
Il est possible de regrouper des threads selon différents
critères. Il suffit de créer un objet de la classe ThreadGroup
et de lui affecter les différents threads. Un objet
ThreadGroup peut contenir des threads mais aussi d'autres
objets de type ThreadGroup.
Groupe de threads par défaut : main
Constructeurs:
ThreadGroup(String nom) création d'un groupe avec attribution
d'un nom
ThreadGroup(ThreadGoup groupe_parent, String nom) création
d'un groupe à l'intérieur du groupe spécifié avec l'attribution d'un
nom
Groupes de threads
Exemple :
package com.moi.test;
public class LanceurDeThreads {
public static void main(String[] args) {
ThreadGroup tg = new ThreadGroup("groupe");
Thread t1 = new Thread(tg,new MonThread3(), "numero 1");
Thread t2 = new Thread(tg,new MonThread3(), "numero 2");
}
}
L'un des avantages de la classe ThreadGroup est de
permettre d'effectuer une action sur tous les threads
d'un même groupe.
Exercice
Producteur-consommateur : un exemple
Un producteur est une thread qui dépose des jetons numérotés dans
un chapeau qui ne peut contenir qu'un seul jeton. Un
consommateur prend ce jeton qui doit être présent dans le
chapeau. Donc :
- le producteur doit s'arrêter de déposer des jetons lorsqu'il y en a
déjà un et doit être informer qu'un jeton a été retiré.
- le consommateur ne peut pas prendre de jeton s'il n'y en a pas
(arrêt du consommateur) et doit être informé lorqu'un jeton a été
déposé.
L'objet le plus à même pour avertir le producteur et le
consommateur est le chapeau lui même.
Exercice
Avec ce même programme, il peut y avoir plusieurs
producteurs et plusieurs consommateur (repérés par
des numéros) mais toujours un seul chapeau ayant un
emplacement pour un seul jeton.
Comme la notification est faite par un get() d'un
consommateur ou un put() d'un producteur, on doit
vérifier si c'est un producteur ou un consommateur
qui a levé l'arrêt ce qui est fait dans le test et qui doit
être refait à chaque déblocage du wait() d'où la
nécessité d'une boucle while et non d'un test if.
JDBC
Le problème de l’accès aux données sans JDBC
Java est un excellent candidat pour le
développement d’applications de bases de données:
robuste et sécurisé
facile à comprendre
automatiquement téléchargeable par le réseau
mais avant JDBC, il était difficile d’accéder à des
bases de données SQL depuis Java :
obligé d’utiliser des API natives comme ODBC
Objectifs de JDBC
Permettre aux programmeurs Java d’écrire un code
indépendant de la base de données et du moyen de
connectivité utilisé
Réalisé par l’API JDBC :
une interface uniforme permettant un accès homogène
aux SGBD
simple à mettre en œuvre
indépendant de la SGBD cible
supportant les fonctionnalités de base du langage SQL
Avantages
Liés a Java :
portabilité sur de nombreux O.S. et sur de
nombreuses SGBDR (Oracle, Informix, Sybase, ..)
uniformité du langage de description des
applications, des applets et des accès aux bases de
données
liberté totale vis a vis des constructeurs
Qu’est ce que JDBC ?
Java DataBase Connectivity (Core API 1.1)
API Java adaptée à la connexion avec les bases de
données relationnelles (SGBDR)
Fournit un ensemble de classes et d’interfaces
permettant l’utilisation sur le réseau d’un ou
plusieurs SGBDR à partir d’un programme Java.
L'architecture JDBC standard
Tout programme comporte 3 composants :
Le code de l'application (ou de l'applet)
Les requêtes doivent être au standard JDBC
Le JDBC Driver Manager
Fourni par SUN
Lien entre l'application et les pilotes (ou drivers) JDBC
Le driver JDBC
Fourni par le fournisseur de la base ou autre
Adapté à la BD
Convertit les requêtes JDBC en requêtes propres à la base
Architecture JDBC
Les types de pilotes JDBC
4 types de drivers (taxonomie de JavaSoft) :
Type I : JDBC-ODBC bridge driver
Type II : Native-API, partly-Java driver
Type III : Net-protocol, all-Java driver
Type IV : Native-protocol, all-Java driver
Tous les drivers :
ttp://www.javasoft.com/products/jdbc/drivers.html
Les types de pilotes JDBC
Il existe quatre types de pilote JDBC :
Type 1 ( JDBC-ODBC bridge ) : le pont JDBC-ODBC qui s'utilise
avec ODBC et un pilote ODBC spécifique pour la base à accéder.
Cette solution fonctionne très bien sous Windows. C'est la solution
idéale pour des développements avec exécution sous Windows d'une
application locale. Cette solution « simple » pour le développement
possède plusieurs
inconvénients :
la multiplication du nombre de couches rend complexe l'architecture (bien
que transparent pour le développeur) et détériore un peu les performances
lors du deploiement, ODBC et son pilote doivent être installé sur tous les
postes ou l'application va fonctionner.
la partie native (ODBC et son pilote) rend l'application moins portable et
dépendant d'une plateforme. ¨
Les types de pilotes JDBC
Type 2 : un driver écrit en java qui appelle l'API native de la base de
données Ce type de driver convertit les ordres JDBC pour appeler
directement les API de la base de données via un pilote natif sur le client. Ce
type de driver nécessite aussi l'utilisation de code natif sur le client.
Type 3 : un driver écrit en Java utilisant le protocole natif de la base de
données
Ce type de driver utilise un protocole réseau propriétaire spécifique à une
base de données. Un serveur dédié reçoit les messages par ce protocole et
dialogue directement avec la base de données. Ce type de driver peut être
facilement utilisé par une applet mais dans ce cas le serveur intermédiaire
doit obligatoirement être installé sur la machine contenant le serveur web.
Type 4 : un driver Java natif
Ce type de driver, écrit en java, appelle directement le SGBD par le réseau.
Ils sont fournis par l'éditeur de la base de données.
Types de drivers et applets
Une application Java peut travailler avec tous les
types de drivers
Pour une applet (untrusted) :
type I ou II : impossible
une applet ne peut pas charger à distance du code natif (non
Java) sur son poste d’exécution
type III : possible
si le serveur middleware se situe au même endroit que le
serveur Web (car communication par sockets avec l’applet)
type IV : possible
si le SGBDR installé au même endroit que le serveur Web
Modèles de connexion en Java
2-tiers : 2 entités interviennent
1. une application Java ou une applet
2. le SGBDR
Modèle 3-tiers : 3 entités interviennent
1. une application Java ou une applet
2. un serveur middleware installé sur le réseau
3. le SGBDR
Enregistrer une base de données dans
ODBC sous Windows 9x ou XP
Enregistrer une base de données dans ODBC
sous Windows 9x ou XP
L’API JDBC
Est fournie par le package java(x).sql
permet de formuler et gérer les requêtes aux bases
de données relationnelles
supporte le standard « SQL-3 Entry Level »
bientôt le niveau supérieur : ANSI SQL-4
Classes/interfaces définissant les objets nécessaires:
à la connexion à une base éloignée
et à la création et exécution de requêtes SQL
L’API JDBC
Disponible en plusieurs versions
JDBC 1 :
Livrée avec JDK 1.1
Tout se trouve dans le package java.sql
JDBC 2 :
2 packages
J2SE contient java.sql (SDK 1.2+)
J2EE contient javax.sql
JDBC 3 :
Avec J2SE, SDK 1.4+
Le cours est basé sur JDBC2
Les classes de l'API JDBC
Les classes de java.sql :
Statement
CallableStatement, PreparedStatement
DatabaseMetaData, ResultSetMetaData
ResultSet,
Connection
Driver
De javax.sql :
RowSet
Datasource
LES CLASSES DE L'API JDBC
Toutes les classes de JDBC sont dans le package
java.sql
Classe Role
DriverManager charge et configure le driver de la base de
données.
Connection réalise la connexion et l'authentification à la
base de données.
Statement ( et PreparedStatement ) contient la requête SQL et la transmet à la
base de données.
ResultSet permet de parcourir les informations
retournées par la base de données
dans le cas d'une sélection de données
Modèle 2-tiers
Principe :
l’application (ou l’applet) cliente utilise JDBC pour parler
directement avec le SGBD qui gère la base de données
Avantages :
simple à mettre en œuvre
bon choix pour des applications clientes peu évoluées, à livrer
rapidement et n’exigeant que peu de maintenance
Inconvénients :
dépendance forte entre le client et la structure du SGBDR
g modification du client si l’environnement serveur change
tendance à avoir des clients « graisseux »
tout le traitement est du côté client
Architecture 2-tiers
Modèle 3-tiers
Principes :
le serveur middleware est l’interlocuteur direct du code Java client;
c’est lui qui échange des données avec le SGBDR
pas forcemment écrit en Java
si c’est le cas : utilise souvent JDBC pour accéder au SGBDR
Avantages:
le middleware peut ajouter un niveau de sécurité
plusieurs supports pour les échanges avec le client :
sockets, RMI Java, CORBA, …
applets : le SGBDR peut se trouver sur une autre machine:
mais serveur Web et middleware au même endroit
facilite l’utilisation de clients « légers »
Modèle 3-tiers
Scénarios d’utilisation
Scénario 1 :
architecture 2-tiers avec une application Java
Scénarios d’utilisation
Scénario 2 :
architecture 2-tiers avec une applet Java
Scénario 3 :
architecture 3-tiers et applet/application Java
La connexion à une base de données
1. Chargement d’un pilote JDBC
2. Définition de l’URL de connexion
3. Etablissement de la connexion
4. Création d’une instruction
5. Exécution de la requête
6. Traitement des résultats
7. Fermeture de la connexion
Chargement d’un pilote JDBC
Pour se connecter à une base de données via ODBC, il faut
tout d'abord charger le pilote JDBC-ODBC qui fait le lien
entre les deux.
L’utilisation de la méthode Class.forName() peut lever une
exception de type ClassNotFoundException, il convient donc
de placer le chargement du pilote dans un bloc sécurisé.
Exemple :
Try {
Class.forName(« oracle.jdbc.driver.OracleDriver ») ;
}
catch(ClassNotFoundException e) {
System.err.println(« Erreur de chargement du driver : + e) ;
}
Définition de l’URL de
connexion.
Afin de localiser votre serveur ou votre base de
données, il est indispensable de spécifier une
adresse sous forme d’URL de type « jdbc: ».
pour une connexion à une base de données en
utilisant un driver JDBC, l’URL se compose
comme suit: jdbc:<sous-protocole>:<nom-BD>?
param=valeur, ...
Exemple:
String url=« jdbc:odbc:Mabase »;
Etablissement de la connexion
La classe DriverManager dispose d’une méthode statique
permettant d’obtenir une connexion à l’URL, la méthode
getConnection() qui retourne un objet de type Connexion.
Cette méthode peut, si la connexion échoue ou si aucun pilote
ne prend en charge l’URL spécifiée, une exception de type
SQLException.
Exemple :
Import java.sql.* ;
…
try {
Connection con = DriverManager.getConnection(url,userId,password) ;
}
catch(SQLException sqle) {
System.err.println(« Erreur lors de la connexion : » + sqle) ;
}
Création d’une instruction.
Afin d’accéder ou de modifier les informations contenues
dans la base de données, il convient d’utiliser un objet de
type Statement.
Une instance de cet objet est retournée par la méthode
Connexion.createStatement() comme ceci :
Statement statement = con.createStatement() ;
3 types de Statement :
Statement : requêtes statiques simples
PreparedStatement : requêtes dynamiques pré-compilées (avec
paramètres d’entrée/sortie)
CallableStatement : procédures stockées
Exécution d’une requête
Pour une requête de type interrogation (SELECT),
la méthode à utiliser de la classe Statement est
exécuteQuery(). retourne un ResultSet (tuples
résultants) Exemple :
String query = "SELECT * FROM Employés";
ResultSet resultset = statement.executeQuery(query);
Pour des traitements de mise à jour, il faut utiliser
la méthode executeUpdate(). retournent un entier
(nombre de tuples traités)
Exemple :
String query = "DELETE FROM Employés WHERE Région =
‘WA’";
int result = statement.executeUpdate(query) ;
Traitement du résultat
Le résultat d'une requête d'intérrogation est renvoyé dans un
objet de la classe ResultSet par la méthode executeQuery().
En ce qui concerne la numérotation des colonnes, elle ne
commence pas à 0 comme pour les tableaux JAVA, mais à 1.
lors de l’exécution de la requête, l’objet ResultSet ne semble
pas positionné sur le premier enregistrement mais avant, dans
une zone que l’on nomme le GAP.
L’objet ResultSet dispose aussi d’un certain nombre de
méthodes permettant de naviguer d’un enregistrement à un
autre. while(resultset.next()) {
System.out.println(resultset.getString(1)) ;
}
la classe ResultSet
Les principales méthodes pour obtenir des données sont :
Méthode Role
getInt(int) retourne le contenu de la colonne dont le numéro est passé en paramètre sous forme
d'entier.
getInt(String) retourne le contenu de la colonne dont le nom est passé en paramètre sous forme
d'entier.
getFloat(int) retourne le contenu de la colonne dont le numéro est passé en paramètre sous forme
de nombre flottant.
getFloat(String)
getDate(int) retourne le contenu de la colonne dont le numéro est passé en paramètre sous forme
de date.
getDate(String)
next() se déplace sur le prochain enregistrement : retourne false si la fin est atteinte
Close() ferme le ResultSet
getMetaData() retourne un objet ResultSetMetaData associé au ResultSet.
JDBC 2.0
La version 2.0 de l'API JDBC a été intégrée au JDK 1.2. Cette nouvelle
version apporte plusieurs fonctionnalités très intéréssantes dont les
principales sont :
support du parcours dans les deux sens des résultats ·
support de la mise à jour des résultats ·
possibilité de faire des mises à jour de masse (Batch Updates) ·
prise en compte des champs définis par SQL-3 dont BLOB et CLOB ·
L'API JDBC 2.0 est séparée en deux parties :
la partie principale (core API) contient les classes et interfaces nécessaires à
l'utilisation de bases de données : elles sont regroupées dans le package java.sql·
la seconde partie est une extension utilisée dans J2EE qui permet de gérer les
transactions distribuées, les pools de connection, la connection avec un objet
DataSource ... Les classes et interfaces sont regroupées dans le package
javax.sql·
JDBC 2.0
Méthode Rôle
boolean isBeforeFirst() renvoie un booleen qui indique si la position courante du
curseur se trouve avant la première ligne
boolean isAfterLast() renvoie un booleen qui indique si la position courante du
curseur se trouve après la dernière ligne
boolean isFirst() renvoie un booleen qui indique si le curseur est positionné sur la première
ligne
boolean isLast() renvoie un booleen qui indique si le curseur est positionné sur la dernière
ligne
boolean first() déplace le curseur sur la première ligne
boolean last() déplace le curseur sur la dernière ligne
boolean absolute() déplace le curseur sur la ligne dont le numéro est fournie en
paramètre à partir du début si il est positif et à partir de la fin si il est négatif. 1
déplace sur la première ligne, -1 sur la dernière, -2 sur l'avant dernière ...
boolean relative(int) déplace le curseur du nombre de lignes fourni en paramètre
par rapport à la position courante du curseur. Le paramètre doit être négatif pour se
déplacer vers le début et positif pur se déplacer vers la fin. Avant l'appel de
cette méthode, il faut obligatoirement que le curseur soit positionné sur une ligne.
boolean previous() déplace le curseur sur la ligne précédente. Le booleen
indique si la première occurrence est dépassée.
JDBC 2.0
void afterLast() déplace le curseur après la
dernière ligne
void beforeFirst() déplace le curseur avant la
première ligne
int getRow() renvoie le numéro de la
ligne courante
JDBC 2.0
Méthode Rôle
updateXXX(String, XXX) permet de mettre à jour la colonne dont le
nom est fourni en paramètre. Le type Java de cette colonne est XXX
updateXXX(int, XXX) permet de mettre à jour la colonne dont
l'index est fourni en paramètre. Le type Java de cette colonne est
XXX
updateRow() permet d'actualiser les modifications
réalisées avec des appels à updateXXX()
boolean rowsUpdated() indique si la ligne courante a été modifiée
deleteRow() supprime la ligne courante
rowDeleted() indique si la ligne courante est supprimée
moveToInsertRow() permet de créer une nouvelle ligne dans
l'ensemble de résultat
inserRow() permet de valider la création de la ligne
Fermeture de la connexion
Pour terminer proprement un traitement, il faut
fermer les différents espaces ouverts
sinon le garbage collector s’en occupera mais moins
efficace
Chaque objet possède une méthode close() :
resultset.close();
statement.close();
connection.close();
PreparedStatement
Lors de l'envoi d'une requête pour exécution 4 étapes doivent être
faites :
analyse de la requête
compilation de la requête
optimisation de la requête
exécution de la requête
et ceci même si cette requête est la même que la précédente !! Or les 3
premières étapes ont déjà été effectuées dans ce cas.
Les bases de données définissent la notion de requête préparée,
requête où les 3 premières étapes ne sont effectuées qu'une seule fois.
modéliser cette notion: l'interface PreparedStatement
interface dérive de l'interface Statement.
PreparedStatement
on ne peut pas avec un Statement construire des
requêtes paramétrées. Il faut pour cela utiliser un
PreparedStatement.
Syntaxe:
PreparedStatement pSmt = conX.prepareStatement("SELECT * FROM
Livres" );
ResultSet rs = pSmt.executeQuery();
Exemple :
PreparedStatement pSmt = conX.prepareStatement("SELECT
nom FROM Personnes WHERE age > ? AND adresse = ?" );
pSmt .setInt(1, 22);
pSmt .setString(2, "Turin");
ResultSet rs = pSmt.executeQuery();//smt.hgfjf fausse
setType(numéroDeLArgument, valeur)
CallableStatement
L'interface CallableStatement définit les méthodes
pour un objet qui va permettre d'appeler une
procédure stockée.
Cette interface hérite de l'interface
PreparedStatement.
Un objet qui implémente l'interface
CallableStatement est obtenu en utilisant la
méthode prepareCall() d'un objet de type
Connection.
Exécution
On lance l'éxécution d'une procédure stockée à l'aide de
la syntaxe :
{call nom_procedure_stockees} : cette forme la plus
simple permet l'appel d'une procédure stockée sans
paramètre ni valeur de retour
{call nom_procedure_stockees(?, ?, ...)} : cette forme
permet l'appel d'une procédure stockée avec des
paramètres·
{? = call nom_procedure_stockees(?, ?, ...)} : cette forme
permet l'appel d'une procédure stockée avec des
paramètre et une valeur de retour·
Exécution
Pour exécuter la requête, l'interface
PreparedStatement propose deux méthodes :
executeQuery() : cette méthode permet d'exécuter une
requête de type interrogation et renvoie un objet de
type ResultSet qui contient les données issues de
l'exécution de la requête·
executeUpdate() : cette méthode permet d'exécuter une
requête de type mise à jour et renvoie un entier qui
contient le nombre d'occurrences impactées par la mise
à jour·
Accès aux méta-données
La méthode getMetaData () permet d’obtenir des
informations sur les types de données du ResultSet
elle renvoie des ResultSetMetaData
on peut connaître entre autres :
le nombre de colonne : getColumnCount()
le nom d’une colonne : getColumnName(int col)
le nom de la table : getTableName(int col)
si un NULL SQL peut être stocké dans une colonne :
isNullable()
ResultSetMetaData
ResultSet rs = stmt.executeQuery("SELECT * FROM emp");
ResultSetMetaData rsmd = rs.getMetatData();
int nbColonnes = rsmd.getColumnCount();
for(int i = 1; i <= nbColonnes; i++) {
// colonnes numerotées à partir de 1 (et non 0)
String nomCol = rsmd.getColumnName(i);
}
DatabaseMetaData
Pour récupérer des informations sur la base de données
elle-même, utiliser la méthode getMetaData() de l’objet
Connection
dépend du SGBD avec lequel on travaille
elle renvoie des DatabaseMetaData
on peut connaître entre autres :
getDriverVersion(), getDriverName(),
getDatabaseProductName(), getDatabaseProductVersion()
les tables de la base : getTables()
le nom de l ’utilisateur : getUserName()
Le composant RowSet
A démarré avec JDBC 2
Interfacé vers un containeur pour tabuler les données
Souvent associé avec un ResultSet
Peut être n'importe quelle donnée, tableau, fichier à
plat, etc.
Étend l'interface de ResultSet
Contient un ensemble complet de propriétés
Supporte les interactions basées sur les évènements
Le composant RowSet (2)
Il a la possibilité de se remplir lui-même avec des
données
Définition de l'emplacement de la base de données
dans une propriété principale
Peut aussi être rempli à partir d'un ResultSet existant
RowSetReader et RowSetWriter
Chaque classe qui implémente une RowSet dispose
d'une lecture et d'une écriture associées :
La lecture extrait les données à partir de la source de
données pour remplir le RowSet : appliquer l'interface
RowsetReader
L'écriture extrait les données du RowSet et les envoie
dans la source de données : appliquer RowSetWriter
Types de RowSet
Les types définis par les fournisseurs :
CachedRowSet :
Déconnecte le RowSet qui stocke ces données dans la mémoire
Ne convient pas à des données volumineuses
Idéal pour les client java légers ou les PDA
JDBCRowSet :
Sert de fin emballage autour du ResultSet
Utilise un driver JDBC
WebRowSet :
Connecte le RowSet qui utilise le protocole HTTP
Permet une interaction avec les servlets à partir du client léger à la
manière d'un tableau
Connexion/déconnexion du RowSet
Les RowSet peuvent être utilisés de la même manière
que les ResultSet standards
Peuvent être reliés à une source de données en
permanence
Peuvent aussi être déconnectés de la source de
données
Se comportent comme source de données pour le client
(données cachées)
Peuvent être séralisés et transmis à travers le réseau
Utile pour les clients légers (PDAs, les périphériques non
connectés)
Cliquez sur l'icône pour ajouter une image
Les Servlets
INTRODUCTION
Une servlet est un programme qui s'exécute côté
serveur en tant qu'extension du serveur.
La technique des CGI en Java, MAIS
Sans créer de processus + toute la puissance de Java
(accès aux divers domaines de l'informatique : BD,
multimédia, réseau, objets distribués, composants, etc.)
+ indépendance de la plate-forme et du serveur
Servlets
Scripts serveur écrit en Java
Servlets de Base : FileServlet, CGIServlet, …
HttpServlet
Exécution dans un espace isolé (Web Application)
Spécification : Sun (sous partie de J2EE)
Implémentation de référence : Apache Group (Jakarta
Tomcat)
Différence avec les CGI et les LD (NSAPI, ISAPI)
performance sur les passages des paramêtres (vs CGI)
sûreté de fonctionnement (NSAPI, ISAPI)
Moteurs de servlets
Pour exécuter des servlets, il faut un moteur de
servlets dans le serveur Web.
Ces moteurs sont des plug-in pour des serveurs Web
existants
ou bien des serveurs Web aux mêmes
Plug-in : deux candidats : Jrun (www.allaire.com),
tomcat (jakarta.apache.org)
Programmation des servlets
Utilise deux paquetages :
javax.servlet : paquetage générique
javax.servlet.http : paquetage pour
serveurs Web
Ces paquetages ne sont pas dans J2SE 1.3
Sont des paquetages supplémentaires.
Il sont aussi intégrés dans J2EE voir à
http://java.sun.com/j2ee/
Exemple de Servlet
Hello World !
import java. io.*;
import javax. servlet.*;
import javax. servlet. http.*;
public class HelloServlet extends HttpServlet {
public void doGet( HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res. setContentType(" text html"); //Set the Content- Type header
PrintWriter out = res. getWriter(); // Get the output
String pname = req. getParameter(" name"); //Get a parameter
if( pname== null) pname=" World !";
out. println("< HTM >");
out. println("< HEAD>< TIT E> Hello, " + pname + "< TIT E>< HEAD>");
out. println("< BODY>");
out. println(" Hello, " + pname);
out. println("< BODY>< HTM >");
out. close();//pas flash?
}
public void doPost( HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException { doGet( req, res); }
}
L'API servlet
L'API servlet regroupe un ensemble de classes dans
deux packages :
javax.servlet : contient les classes pour développer des
serlvets génériques indépendantes d'un protocole.
javax.servlet.http : contient les classes pour développer
des servlets qui reposent sur le protocole http utilisé
par les serveurs web.
L'API servlet
L'API servlet
javax.servlet Nom Role
RequestDispatcher Définition d'un objet qui permet le renvoi d'une
requête vers une autre ressource du serveur (une
autre servlet, une JSP ...)
Servlet Définition de base d'une servlet
ServletContext Définition d'un objet pour obtenir des
informations sur le contexte d'execution de la
servlet
Les
interfaces
ServletConfig Définition d'un objet pour configurer la servlet
ServletRequest Définition d'un objet contenant la requête du
client
ServletResponse Définition d'un objet qui contient la reponse
renvoyée par la servlet
SingleThreadMode Permet de définir une servlet qui ne répondra qu'à
l une seule requête à la fois
L'API servlet
javax.servlet Nom Role
GenericServlet Classe définissant une servlet indépendante de
tout protocole
ServletInputStream Flux permet la lecture des donnes de la requête
Les classes cliente
ServletOutPutStream Flux permettant l'envoie de la reponse de la
servlet
SevletException Exception générale en cas de problème durant
Les l'exécution de la servlet
exceptions UnavailableExceptio Exception levée si la servlet n'est pas
n disponible
L'API servlet
javax.servlet. Nom Role
http
HttpServletRequest Hérite de ServletRequest : définit un objet
contenant une requête selon le protocole http
HttpServletRespons Hérite de ServletResponse : définit un objet
Les interfaces e contenant la reponse de la servlet selon le
protocole http
HttpSession Définit un objet qui représente une session
Cookie Classe représentant un cookie (ensemble de
données sauvegardées par le brower sur le poste
client)
Les classes
HttpServlet Hérite de GenericServlet : classe définissant une
servlet utilisant le protocole http
HttpUtils Classe proposant des méthodes statiques utiles
pour le développement de servlet http
L'interface Servlet
Cette interface définit 5 méthodes qui permettent au conteneur web
de dialoguer avec la servlet:
void service (ServletRequest req,ServletResponse res)
void init(ServletConfig conf)
ServletConfig getServletConfig()
void destroy()
String getServletInfo()
Les méthodes init(), service() et destroy() assurent le cycle
de vie de la servlet en étant respectivement appelées lors de
la création de la servlet, lors de son appel pour le traitement
d'une requête et lors de sa destruction.
La requête et la réponse
L'interface ServletRequest définit plusieurs méthodes qui permettent
d'obtenir des données sur la requête du client :
ServletInputStream getInputStream()
//Permet d'obtenir un flux pour les données de la requête
BufferedReader getReader()
//Idem
L'interface ServletResponse définit plusieurs méthodes qui permettent
de fournir la réponse faite par la servlet suite à ces traitements :
SetContentType //Permet de préciser le type MIME de la réponse
ServletOutputStream getOutputStream() // Permet d'obtenir un flux
pour envoyer la réponse
PrintWriter getWriter() //Permet d'obtenir un flux pour
envoyer la réponse
Gestion des servlets
Les états d'une servlet
les états d'une applet. Le passage d'un état à un autre est automatique fait par le
conteneur de servlets.
Une servlet doit implémenter l'interface
javax.servlet.http
Elle doit comporter l’une des deux méthodes :
doGet() pour les requêtes http de type GET
doPost() pour les requêtes http de type POST
Récupération de paramètres
public void doGet(HttpServletRequest req,
HttpServletResponse rep)
throws ServletException, IOException{
Enumeration liste = req.getParameterNames();
String [] valeurs = req.getParameterValues();
String val1 = req.getParameter(''param1'');
Exemple : annuaire Mastere
<HTML>
<HEAD><TITLE> ANNUAIRE Mastere </TITLE></HEAD>
<BODY BGCOLOR="#FFFFFF"<CENTER>
<CENTER><H1>ANNUAIRE DU DESS TIIR </H1></CENTER>
<HR><CENTER>
<H2>Recherche de coordonnées </H2></CENTER>
<P> Tapez le début du nom de la personne recherchée:
<P><FORM METHOD=POST
ACTION=http://localhost:8080/examples/servlets/annuaire
method=post>
<INPUT TYPE=TEXT NAME="nom" SIZE=20 MAXLENGTH=30 VALUE="">
<P><INPUT TYPE=SUBMIT NAME="go" VALUE="RECHERCHER">
<INPUT TYPE=RESET NAME="reset" VALUE="ANNULER">
</FORM>
</BODY></HTML>
Annuaire Mastere(Servlet)
import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class Annuaire extends HttpServlet{
public void doPost( HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException{
res.setContType("text/html");
PrintWriter out=res.getWriter();
out.println("<HEAD><TITLE>Réponse annuaire </TITLE></HEAD><BODY>");
out.println("<HR>");
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
String url ="jdbc:odbc:mabase";
java.sql.Connection c=DriverManager.getConnection(url,"","");
Annuaire Mastere(Servlet)-Suite-
java.sql.Statement st = c.createStatement();
java.sql.ResultSet rs =
st.executeQuery("Select * from matable where nom like '"
+req.getParameter("nom"+"*'"));
rs.next();
out.println(rs.getString("prenom")+" "+rs.getString("nom") );
}
catch (SQLException e){
out.println("Cette personne n'existe pas");
}
out.println("<P><A href = annuaire.html> Retour</A>"</P>);
out.println("</BODY>");
out.close();
}
public String getServletInfo(){
return "Servlet Annuaire";
}
Les cookies
Ajout de cookies à l ’entête de la réponse
void HttpServletResponse. addCookie( Cookie
cookie)
Le cookie peut être un cookie récupéré dans la requête
Et modifié avant d’être ajouté à la réponse
Sessions : javax. servlet. http. HttpSession
Garder la mémoire des informations d'une page à l'autre :
Utiliser les cookies (sécurité!)
Syntaxe CGI : paramètres dans l'URL
Champs ``HIDDEN'' de formulaires
<INPUT TYPE=''HIDDEN'' NAME=''PARAM1''VALUE=''VAL1''>
Objet HttpSession
HttpSession session=request.getSession(true);
Classe objet = (Classe) session.getValue(''param1'');
Méthodes : getValue(), putValue(), removeValue()
HttpSession session = req.getSession(true);
If (session.isNew()){
session.putValue('‘toto'', new int[] {0});
}
Int[] toto = (int[]) session.getValue('‘toto'');
Le suivi de session
Le serveur maintient une session de 2 manières :
Cookie (Name: SESSIONID Value: To1010mC8601021835741167At)
les cookies peuvent être désactivés sur le navigateur
Réécriture des URLs
Ouverture/récupération d ’une session
javax. servlet. http. HttpSession session = req. getSession( false);
// la session est récupérée ou null si elle n ’existait pas déjà
javax. servlet. http. HttpSession session = req. getSession( true);
//la session est récupérée ou ouverte si elle n ’existait pas déjà
Invalidation d ’une session
javax. servlet. http. HttpSession session = req. getSession( false);
session. invalidate(); la session est invalidée ( i. e. fermée)
Information sur la session
javax. servlet. http. HttpSession session = req. getSession( false);
L ’identifiant
String sessionid= session. getId(); // par exemple: To1010mC8601021835741167At
La date de création
long datecreation= session. getCreationTime(); // nb de ms depu s 1/ 1/ 1970: 00: 00
La date du dernier accès
long datelastaccess= session. get astAccessedTime();
Exemple
HttpSession session = req. getSession( true);
if( session. get astAccessedTime() - session. getCreationTime() > 5* 60* 1000 ) {
session. invalidate();
}
Information sur la session
javax. servlet. http. HttpSession session = req. getSession( false);
Méthode de suivi de session
boolean HttpServletRequest. isRequestedSessionIdFromCookie()
// test si le suivi de session utilise un cookie
boolean HttpServletRequest. isRequestedSessionIdFromUR ()
// test si le suivi de session utilise la réécriture d ’UR
Réécriture des URL (cas isRequestedSessionIdFromURL )
les URL générées doivent être encodées pour intégrer le suivi de session
String HttpServletResponse. encodeRedirectUR (String url)
String HttpServletResponse. encodeUR (String url)
Exemple
res. sendRedirect( res. encodeRedirectUR (" servlet login");
Liaison d ’objets à une session
javax. servlet. http. HttpSession session = req.
getSession( true);
Ajout/remplacement d ’une valeur
void HttpSession. setAttribute( String name, Object value)
Suppression d ’une valeur
void HttpSession. removeAttribute( String name)
Récupération des valeurs/d ’une valeur
String[] HttpSession. getAttributeNames()
Object HttpSession. getAttribute( String name)
Exemple de liaison d ’objets
import mycybermarket. Cart; …
public void doGet( HttpServletRequest req, HttpServletResponse res) … {
Cart cart;
HttpSession session = req. getSession( true);
if(( cart=( Cart) session. getAttribute(" CART"))!= null) {
cart= CartFactory. create(); // new rt( ... ); ou = c rtHome. cre te();
session. setAttribute("CART", cart);
} ...
...
if( action. equals(" exit") {
cart. releaseProducts();
session. removeAttribute(" CART");
}
...
Observateurs sur la session
Motivations
réagir face à des événements intervenants dans la/les sessions
4 interfaces Listeners
HttpSessionActivationListener
la session peut être passivée puis réactivée
HttpSessionListener
changement sur la liste des sessions actives de l'application Web.
HttpSessionAttributeListener
changement sur les attributs d’une des sessions de l’application
Web.
HttpSessionBindingListener
un objet peut être notifié de sa liaison rupture à un session
Observateurs sur la session
HttpSessionActivationListener
la session peut être passivée puis réactivée
void sessionDidActivate( HttpSessionEvent se)
void sessionWillPassivate( HttpSessionEvent se)
HttpSessionListener
changement sur la liste des sessions actives de l'application Web.
void sessionCreated( HttpSessionEvent se)
Void sessionDestroyed( HttpSessionEvent se) invalidation
HttpSessionAttributeListener
attribute lists of sessions within this web application.
void attributeAdded( HttpSessionBindingEvent se)
void attributeRemoved( HttpSessionBindingEvent se)
void attributeReplaced( HttpSessionBindingEvent se)
HttpSessionBindingListener
un objet peut être notifié de sa liaison rupture à un session
void valueBound( HttpSessionBindingEvent event)
void valueUnbound( HttpSessionBindingEvent event)
Observateur de liaison
Motivations
faire réagir les objets liés aux liaisons et « déliaisons »
fermer des fichiers, des connexions, valider des transactions, ...
API
interface HttpSessionBinding istener
public void valueBound( HttpSessionBindingEvent event)
public void valueUnbound( HttpSessionBindingEvent event)
class HttpSessionBindingEvent extends EventObject
public Session getSession() la session concernée
public String getName() le nom de la liaison
Principe
l ’objet lié doit implanté HttpSessionBinding istener
valueBound () est invoqué quand l ’objet est lié ( putValue ())
valueUnbound () est invoqué quand la session est invalidé ou expire ou quand l ’objet est
délié ( setAttribute ()/ removeAttribute ()).
Exemple de Observateur de
Liaison
class CartBinding istener implements HttpSessionBindingListener {
rt c rt= null;
public CartBinding istener( ... ) { this. cart = new Cart( ... ); }
public void valueBound( HttpSessionBindingEvent event) {}
public void valueUnbound( HttpSessionBindingEvent event) {
cart. releaseProducts();}
public void doGet( HttpServletRequest req, HttpServletResponse res) {
CartBinding istener cart;
HttpSession session = req. getSession( true);
CartBinding istener cart=( Cart) session. getValue(" CART");
if( cart== null) { cart= new CartBinding istener( ... );
session. setAttribute(" CART", cart); // v lueBound est invoqué sur l ’objet lié
}…
session. removeAttribute (" CART"); // v lueUnbound est invoqué sur l ’objet lié
Partage d ’objets entre servlets
Motivation
partager une information commune entre servlets, ...
Plusieurs
S1 : utilisez les Properties de java. lang. System
S2 : classe commune avec des membres statiques
S3 : utilisez le contexte de l’application
Partage d ’objets entre servlets
Solution 1 : utilise les Properties de java. lang. System
String java. lang. System. getProperty( String key)
String java. lang. System. setProperty( String key, String value)
Remarque : les Properties sont partagées par toutes les WebApps du
serveur J2EE
Solution 2 : classe commune avec des membres statiques
l ’initialisation des membres statiques XXX peut se faire au moment du
premier accès par une des servlets
Remarque pour une meilleure programmation
les membres statiques sont privés et sont accédés par des méthodes
statiques setXXX() et getXXX()
la classe n ’est accessible que par les servlets du même package et chargée
par le même ClassLoader (un par WebApp)
Partage d ’objets entre servlets
Solution 3 : utiliser les <env- entry> du contexte JNDI de l’application
Paires typées (name, value, classname) appartenant au contexte de l’application
Web
<env- entry>
<env- entry- name> defaultCurrency< env- entry- name>
<env- entry- value> EUR< env- entry- value>
<env- entry- type> java. lang. String< env- entry- type>
< env- entry>
<env- entry>
<env- entry- name> default anguage< env- entry- name>
<env- entry- value> 33< env- entry- value>
<env- entry- type> java. lang. Integer< env- entry- type>
< env- entry>
Partage d ’objets entre servlets
Récupération des <env- entry> via JNDI
Context ctx = new InitialContext();
Object value = ctx. lookup(" java: comp env defaultCurrency");
out. println(" Default currency value : " + value);
Context envCtx = ( Context) ctx. lookup(" java: comp env ");
NamingEnumeration enum = ctx. list(" java: comp env ");
while (enum. hasMoreElements()) {
out. print(" Binding : "+ ( enum. nextElement(). toString());
}
NamingEnumeration enumbinding = envCtx. listBindings(" java: comp env
");
while (enumbinding. hasMoreElements()) {
out. print(" Binding : "+( enumbinding. nextElement(). toString());
Authentification
Authentification
• Système :
HttpServletRequest. getAuthType(), HttpServletRequest. getRemoteUser()
HTTP - BASIC ou DIGEST challenge
WWW-Authenticate
SSL 3.0 authentifie le client
Custom
utilise des servlets vérifiant l’identité de l ’utilisateur avec des moyens
externes au serveur (annuaire LDAP, BD, GSM, …)
Autres
java. security. Principal HttpServletRequest. getUserPrincipal()
//identité de l ’utilisateur dans le schéma général sécurité de java
boolean HttpServletRequest. isUserInRole( String role)
//test si l ’utilisateur appartient à un role (i. e. classe d ’utilisateur)
Request Dispatch
Redirige la traitement de la requête vers une autre
servlet ou JSP
Utilisé pour le MVC
Exemple
public class ForwardServlet extends HttpServlet {
public void doGet (HttpServletRequest request,
HttpServletResponse response) {
//Set the attribute and forward to hello. jsp
request. setAttribute (" action", " hello");
ServletContext context= getServletConfig(). getServletContext().
context. getRequestDispatcher(" hello. jsp"). forward( request,
response);
}
}
Java Server Pages (JSP)
Principe
Server Side Script
Insertion de SSS (syntaxe Java) dans les pages HTML
Avantage par rapport aux servlets
Ecriture moins verbeuse Orientée Web Designer
Insérable par des outils auteurs dans le code de pages HTML
Extensible grâce aux JSTL
Spécification
JSR-52
JSR-152 JavaServer Pages 2.0 Specification
Implémentations
J2EESDK et Jakarta JASPER/TomCat
JSP vs Active Server Pages (ASP)
ASP est une technologie comparable à JSP développé par
Microsoft. Cependant, deux avantages sont dégagés par
JSP. Premièrement, les parties dynamiques sont
développées en JAVA et non en VisualBasic ou d’autres
langages spécifiques à Microsoft donc plus performantes
et faciles à utiliser. Deuxièmement, JSP est compatible
avec d’autres systèmes d’exploitation et serveurs web
développés par d’autres compagnies que Microsoft.
JSP vs JavaScript
JavaScript peut générer dynamiquement du HTML sur le
côté client. Cette une fonctionnalité très utile mais elle gère
les situations où les informations se trouvent sur le côté
client seulement. De plus, le fait que les programmes
JavaScript s’exécutent sur le côté client, ils ne peuvent
accéder aux ressources situées sur le côté serveur comme
une base de données, un catalogue d’information, etc.
Insertion des scripts
Directives
<%@page import="java.util.*" %>
<%@taglib prefix="c" uri="WEB-INF/tld/core.tld" %>
Éléments de script
Scriplets <% code java %>
Déclarations <%! Déclarations %>
Expressions <%= expression %>
TagLib
<jsp:forward page="forward.jsp" />
<jsp:include page="result.jsp" />
<c:if test="${applicationScope:booklist == null}" >
<c:import url="/books.xml" var="xml" />
<x:parse xml="${xml}" var="booklist" scope="application" />
</c:if>
Exemple
<HTML >
<HEAD>< TITLE> Hello< TITLE>< HEAD>
<BODY>
<H1> Salut
<%
String pname; //déclaration de variable
pname = request. getParameter(" name"); // request : objet implicite
if ( pname== null) { out. println(" World"); } else {
%>
Mr <%= pname%>
<% } // fin du else %>
< H1>
< BODY>< HTML >
Exemple de traitement d ’un formulaire
<%@ method = " doPost" %>
<HTM >
<HEAD>< TITLE> Hello< TITLE>< HEAD>
<BODY>
<H1> Hello
<%
String pname; //déclaration de variable
pname = request. getParameter(" name"); //request : objet implicite
if ( pname== null) { out. println(" World"); } else {
%>
Mr <%= pname%>
<% } // fin du else %>
< H1>
< BODY>< HTML >
JSP : Exemple avec une session
JSP listant un « caddie » virtuel
<html>
<jsp: useBean id=" cart" scope=" session" class=" mycybermarket. MyCart" >
<jsp: setProperty name=" cart" property="*" >
<%
cart. processRequest( request);
%>
<br> You have the following items in your cart:
<ol>
<% String[] items = cart. getItems();
for ( int i= 0; i< items. length; i++) { %>
<li> <%= items[ i] %>
<% } %>
< ol>< hr>
<%@ include file =" catalog. html" %>
< html>
JSP : Exemple avec une session
Classe de « caddie » utilisé par la JSP
Génération des JSP
Compilation des JSP en classes Java
génération et compilation d ’une classe étendant
HttpJspBase à la première invocation.
Au runtime
la servlet JspServlet invoque le compilateur Jasper
puis charge et exécute la méthode _jspService de la
classe HttpJspBase générée
Avant déploiement
Les JSP peuvent être aussi générées avant le
déploiement (tâche <jspc>)
Architecture
Action jsp:forward
Cette action vous permet de rediriger une requête
vers une autre page.
Syntaxe:
<jsp:forward page="{relativeURL | <%= expression %>}" />
ou
<jsp:forward page="{relativeURL | <%= expression %>}" >
<jsp:param name="parameterName"
value="{ parameterValue | <%= expression %>}" /> +
</jsp:forward>
Action jsp:include
Comme vu précédemment, l’action include vous permet d’insérer
un fichier pendant que le servlet est généré à partir du fichier JSP.
<jsp:include page="relative URL" flush="true" />
Contrairement à la directive include qui insère les fichiers au
moment où le fichier JSP est compilé sur le serveur et transformé
en servlet, l’action include insère les fichiers seulement
lorsqu’une requête est placée sur la page demandée. Ceci en
coûte une légère perte en performance mais gagne en flexibilité.
Session JSP
GetName.html SaveName.jsp
<% String name =
<HTML> request.getParameter( "username" );
<BODY> session.setAttribute( "theName", name ); %>
<FORM METHOD=POST
ACTION="SaveName.jsp"> NextPage.jsp
What's your name? <INPUT <HTML>
TYPE=TEXT NAME=username <BODY> Hello, <%=
session.getAttribute( "theName" ) %>
SIZE=20> <P> </BODY>
<INPUT TYPE=SUBMIT> </HTML>
</FORM>
</BODY>
</HTML>
<jsp:useBean>
Le tag <jsp:useBean>
Le tag <jsp:useBean> permet de localiser une instance ou d'instancier un
bean pour l'utiliser dans la JSP. Ce tag ne permet pas de traiter
directement des EJB.
<jsp:useBean>
La syntaxe est la suivante :
<jsp:useBean
id="beanInstanceName"
scope="page|request|session|application"
{ class="package.class" | •L'attribut id permet de donner un nom à la
type="package.class" |
variable qui va contenir la référence sur le
bean.
class="package.class" type="package.class" |
beanName="{package.class | <%= expression %>}" type="package.class"
}
•L'attribut class permet d'indiquer la classe du bean.
{ /> |
•L'attribut type permet de préciser le type de la variable qui va
> ... contenir la référence du bean. La valeur indiquée doit
</jsp:useBean> obligatoirement être une super classe du bean ou une interface
} implémentée par le bean (directement ou par héritage)
•L'attribut beanName permet d'instancier le bean grâce à la
méthode instanciate() de la classe Beans.
<jsp:useBean>
L'attribut scope permet de définir la portée durant laquelle le
bean est défini et utilisable. La valeur de cette attribut
détermine la manière dont le tag localise ou instancie le bean.
Les valeurs possibles sont :
Valeur Rôle
page Le bean est utilisable dans toute la page JSP ainsi que dans les fichiers statiques
inclus. C'est la valeur par défaut.
request le bean est accessible durant la durée de vie de la requête. La méthode
getAttribute() de l'objet request permet d'obtenir une référence sur le bean.
session le bean est utilisable par toutes les JSP qui appartiennent à la même session que la
JSP qui a instanciée le bean. Le bean est utilisable tout au long de la session par
toutes les pages qui y participent. La JSP qui créé le bean doit avoir l'attribut
session = « true » dans sa directive page.
application le bean est utilisable par toutes les JSP qui appartiennent à la même application
que la JSP qui a instanciée le bean. Le bean n'est instancié que lors du
rechargement de l'application.
Exemple
Personne.java
TestBean.jsp
package test;
<html> public class Personne {
<HEAD> private String nom;
<TITLE>Essai d'instanciation d'un bean dans une private String prenom;
JSP</TITLE> public Personne() {
</HEAD> this.nom = "nom par defaut";
<body> this.prenom = "prenom par defaut";
}
<p>Test d'utilisation d'un Bean dans une JSP </p>
public void setNom (String nom) {
<jsp:useBean id="personne" scope="request" this.nom = nom;
class="test.Personne" /> }
<p>nom initial = <%=personne.getNom() %></p> public String getNom() {
<% return (this.nom);
personne.setNom("mon nom"); }
%> public void setPrenom (String prenom) {
this.prenom = prenom;
<p>nom mise à jour = <%= personne.getNom()
}
%></p> public String getPrenom () {
</body> return (this.prenom);
</html> }
}
Formulaire d'échange avec une BD
<HTML><HEAD><Title> Essai de connexion </title></HEAD>
<BODY bgcolor="#FFFFFF">
<%@ page import="java.sql.*" errorPage="erreur.jsp" %>
<%!
Connection con=null;
public void JspInit(){
String url="jdbc:odbc:musiciens";
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
con=DriverManager.getConnection(url,"","");
}
catch (Exception e){
System.err.println(e.getMessage());
}
}
public void jspDestroy(){
try{con.close();}
catch (SQLException e)
{System.err.println(e.getMessage());}
}
%>
Formulaire d'échange avec une BD
<% String pnom = request.getParameter("nom"); <br>
String nom = ""; String prenom = ""; <%="nom "+nom + " " %> <
String adresse =""; String ville = ""; %="Ville "+ville %>
String requete = ""; <br>
try{ <%
Statement stmt = con.createStatement(); stmt.close();
requete="select * from personnes where nom }
="+pnom; catch(SQLException ex){
ResultSet rs =stmt.executeQuery(requete);
if (rs.next()) { System.err.println("SQLExceptio
nom = rs.getString("NOM"); n : "+
prenom = rs.getString("PRENOM"); ex.getMessage());
adresse = rs.getString("ADRESSE"); }
ville = rs.getString("VILLE"); %>
}%>
Formulaire d'échange avec une BD
<form action= saisie.jsp method="post">
<input type="text" name="pnom"> Entrez un nom
<input type="submit" value="valider">
</form>
</body>
</HTML>
Remarque : les méthodes jspInit et jspDestroy
doivent être redéfinies en surcharge de façon à
éviter l'ouverture et la fermeture systématique de la
base lors du traitement de chaque requête.
Définition
Selon la spécification des Javabeans, une Bean est un
composant logiciel réutilisable pouvant être manipulé
visuellement dans un outil de construction ( builder
tool ).
Les EJB et les beans n'ont en commun que d'être des
composants. Les java beans sont des composants qui
peuvent être utilisés dans toutes les circonstances. Les
EJB doivent obligatoirement s'exécuter dans un
environnement serveur dédié.
Les EJB s'exécutent dans un environnement particulier :
le serveur d'EJB.
La technologie Enterprise JavaBeans (EJB) est une
architecture de composants logiciels côté serveur
pour la plateforme J2EE.
Composant logiciel. Un composant logiciel est une unité
de composition dotée d’interfaces spécifiées. Un
composant logiciel peut être déployé indépendamment
et être sujet à une composition par une tierce entité.
Le point clé des technologies basées composant est la
réutilisabilité, le composant doit être capable de
s’autodécrire et de se déployer indépendamment des
autres parties de l’application.
Les EJB s'exécutent dans un environnement particulier : le
serveur d'EJB.
Le serveur d'EJB fournit un ensemble de fonctionnalités utilisées
par un ou plusieurs conteneurs d'EJB qui constituent le serveur
d'EJB.
Serveur
EJBConteneur
d’EJB
EJ EJ
B B
Client Browser Base de
ou application données
Conteneur d’EJB
EJ EJ
EJ
B B
B
Conteneur d'EJB
Le conteneur d'EJB propose un certain nombre de
services qui assurent la gestion :
du cycle de vie du bean ·
de l'accès au bean ·
de la sécurité d'accès ·
des accès concurrents ·
des transactions ·
Développement d'un EJB
Le cycle de développement d'un EJB comprend :
la création des interfaces et des classes du bean.
le packaging du bean sous forme de fichier archive jar.
le déploiement du bean dans un serveur d'EJB.
le test du bean.
Création d'un bean
La création d'un bean nécessite la création d'au
minimum deux interfaces et une classe pour
respecter les spécifications de Sun :
la classe du bean,
l'interface remote
l'interface home
L'interface remote
L'interface remote permet de définir l'ensemble des
services fournis par le bean. Cette interface étend
l'interface javax.ejb.EJBObject.
Dans la version 2.0 des EJB, l'API propose une
interface supplémentaire, EJBLocalObject, pour
définir les services fournis par le bean qui peuvent
être appellés en local par d'autres beans.
L'interface remote
L'interface javax.ejb.EJBObject définit plusieurs méthodes qui seront donc
présentes dans tous les EJB :
EJBHome getEJBHome() throws java.rmi.RemoteException : renvoie une
référence sur l'objet Home ·
Handle getHandle() throws java.rmi.RemoteException : renvoie un objet
permettant de sérialiser le bean ·
Object getPrimaryKey() throws java.rmi.RemoteException : renvoie une
référence sur l'objet qui encapsule laclé primaire d'un bean entité·
boolean isIdentical(EJBObject) throws java.rmi.RemoteException : renvoie un
boolean qui précise si le bean est identique à l'instance du bean fourni en
paramètre. Pour un bean session sans état, cette méthode renvoie toujours true.
Pour un bean entité, la méthode renvoie true si la clé primaire des deux beans est
identique.
void remove() throws java.rmi.RemoteException, javax.ejb.RemoveException :
cette méthode demande la destruction du bean. Pour un bean entité, elle provoque
la suppression des données coorespondantes dans la base de données.
L'interface home
L'interface home permet de définir l'ensemble des services qui vont
permettre la gestion du cycle de vie du bean. Cette interface étend
l'interface EJBHome.
La création d'une instance d'un bean se fait grâce à une ou plusieurs
surcharges de la méthode create(). Chacune de ces méthodes renvoie une
instance d'un objet du type de l'interface remote.
L'interface javax.ejb.EJBHome définit plusieurs méthodes :
EJBMetaData getEJBMetaData() throws java.rmi.RemoteException
HomeHandle getHomeHandle() throws java.rmi.RemoteException // renvoie un
objet qui permet de sérialiser l'objet implémentant l'interface EJBHome
void remove(Handle) throws java.rmi.RemoteException,
javax.ejb.RemoveException // supprime le bean
void remove(Object) throws java.rmi.RemoteException,
javax.ejb.RemoveException // supprime le bean entité dont l'objet encapsulant la
clé primaire est fourni en paramètre
La classe du bean
La classe du bean contient l'implémentation des
traitements du bean. Cette classe implémente les
méthodes déclarées dans les interfaces home et
remote. Les méthodes définissant celle de
l'interface home sont obligatoirement préfixées par
"ejb".
Les différents types d’EJB
Il existe trois sortes d’EJB, chacun ayant une fonction
bien précise. Leur utilisation impose une bonne
conception et une certaine modularité dans l’application.
Session Beans. Les beans sessions encapsulent le coeur des
traitement, on parle aussi de composants “métiers”
Message Driven Beans. Les MDB permettent de recevoir des
messages de manière asynchrone (méthode onMessage() de
l’interface MessageListener). Ils invoquent ensuite des
méthodes sur les beans sessions. (seulement dans EJB2.0)
Entity Beans. Les beans entit´es permettent de gérer la
persistance et la consultation des données de manière
transparente.
Les EJB session
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.)
Les EJB session
Un EJB session est un EJB de service dont la durée
de vie correspond à un échange avec un client. Ils
contiennent les règles métiers de l'application. Il
existe deux types d'EJB session :
sans état (stateless)
avec état (statefull)
EJB session stateless
Ce type de bean propose des services sous la forme
de méthodes. Il ne peut pas conserver de données
entre deux appels de méthodes. Les données
provenant du client nécessaires aux traitements
d'une méthode doivent obligatoirement être
fournies en paramètre de la méthode.
Exemple stateless
package com.moi.ejb;
import java.rmi.RemoteException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class MonPremierEJBBean implements SessionBean {
public String message() {
return "Bonjour";
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void ejbRemove() {
}
public void setSessionContext(SessionContext arg0) throws EJBException,
RemoteException {
}
public void ejbCreate() {
}
}
Les EJB session Statefull
Ce type de bean fourni aussi un ensemble de traitements
via ces méthodes mais il a la possibilité de conserver des
données entre les différents appels de méthodes d'un même
client. Une instance particulière est donc dédiée à chaque
client qui sollicite ces services et ce tout au long du
dialogue entre les deux entités.
Les données conservées par le bean sont stockées dans les
variables d'instances du bean. Les données sont donc
conservées en mémoire.
Généralement, les méthodes proposées par le bean
permettent de consulter et mettre à jour ces données.
Les EJB entité
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 EJB2.0
Les EJB entité
Les EJB entité permettent de représenter et de gérer des données
enregistrées dans une base de données. Ils implémentent
l'interface EntityBean.
Les beans entité assurent la persistance des données en
représentant tout au partie d'une table ou d'une vue. Il existe
deux types de bean entité :
persistance gérée par le conteneur (CMP : Container Managed
Persistence)
persistance gérée par le bean (BMP : Bean Managed Persistence)
Plusieurs clients peuvent accéder simultanément à un
même EJB entity. La gestion des transactions et des accès
concurrents est assurée par le conteneur.
Entity Beans
Les Entity Beans servent à manipuler de manière
transparente des données.
On a généralement un type d’Entity Bean par table
d’une base de données relationnelle.
A un moumment donné, une instance d’Entity Bean
correspond à un enregistrement de cette table.
Il suffit alors de manipuler le bean entité pour
manipuler les données sous-jacentes.
Message Driven Beans
Nouveau dans EJB 2.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…
Message Driven Beans
La communication avec les Entity Beans ou avec les Session
Beans se fait par invocation de méthode à distance (mode
synchrone).
Les Message Driven Beans permettent au contraire d’utiliser
des envois de messages pour la communication (mode
asynchrone). Les messages peuvent par ailleurs encapsuler,
ou d´eclencher des appels de méthodes sur des sessions et/ou
des entity beans, ce qui permet de les manipuler de maniére
asynchrone et de gérer des files d’attentes.
Tout MDB implémente l’interface
javax.jms.MessageListener, qui posséde une méthode
onMessage(Message)
Ecriture d'un premier Bean
Ordre typique des opérations
1. Ecrire les fichiers .java qui composent le bean,
2. Ecrire le descripteur du bean,
3. Compiler les .java de l'étape 1,
4. Créer un .jar contenant les .class et le descripteur,
5. Deployer le .jar (via outil ou simple copie),
6. Vérifier que le serveur fonctionne et a bien déployé le
bean, sinon, vérifier la config,
7. Ecrire, compiler, exécuter 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;
}
L'interface Home locale
package examples;
/**
* This is the local home interface for HelloBean.
* This interface is implemented by the EJB Server's
* tools - the implemented object is called the
* local home object, and serves as a factory for
* EJB local objects.
*/
public interface HelloLocalHome extends javax.ejb.EJBLocalHome {
/*
* This method creates the EJB Object.
*
* @return The newly created EJB Object.
*/
HelloLocal create() throws javax.ejb.CreateException;
}
La classe du bean
package examples; public void
/** setSessionContext(javax.ejb.SessionC
* Demonstration stateless session bean. ontext ctx) {
*/ this.ctx = ctx;
public class HelloBean implements javax.ejb.SessionBean
{
}
private SessionContext ctx; //
// // Business methods
// EJB-required methods //
// public String hello() {
public void ejbCreate() { System.out.println("hello()");
System.out.println("ejbCreate()"); return "Hello, World!";
}
}
public void ejbRemove() {
System.out.println("ejbRemove()"); }
}
public void ejbActivate() {
System.out.println("ejbActivate()");
}
public void ejbPassivate() {
System.out.println("ejbPassivate()");
}
La classe du bean
ejbCreate() correspond au create() de l'interface
Home
Une seule méthode métier : 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.
…
Les EJBContexts : le lien avec le container
Sert à encapsuler le domaine dans lequel évolue le
bean dans un objet.
setSessionContext() appelé par le container.
Un contexte par type de Bean
SessionContext, EntityContext, MesageDrivenContext
Méthodes correspondantes setSessionContext(),
setEntityContext(), setMessageDrivenBeanContext()
Les EJBContexts : le lien avec le container
public interface javax.ejb.EJBContext { * These are transaction methods
/* */
* Call these from within your bean to public boolean getRollbackOnly();
access public void setRollbackOnly();
* your own home object or local home public javax.transaction.UserTransaction
object. getUserTransaction();
* /*
* You can use them to create, destroy, or * These are security methods -
* find EJB objects and EJB local objects */
* of your own bean class type. public boolean
*/ isCallerInRole(java.lang.String);
public javax.ejb.EJBHome public java.security.Principal
getEJBHome(); getCallerPrincipal();
public javax.ejb.EJBLocalHome }
getEJBLocalHome();
Le descripteur de déploiement
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise
JavaBeans 2.0//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_2_0.dtd">
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Hello</ejb-name>
<home>examples.HelloHome</home>
<remote>examples.Hello</remote>
<local-home>examples.HelloLocalHome</local-home>
<local>examples.HelloLocal</local>
<ejb-class>examples.HelloBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>
Le fichier .jar de l'EJB
Il faut mettre tous les fichiers compilés + descripteurs
dans un .jar
Depuis un IDE ou à la main
jar cf HelloWorld.jar *
Contenu de HelloWorld.jar
META-INF/MANIFEST.MF
META-INF/ejb-jar.xml
examples/HelloBean.class
examples/HelloLocalHome.class
examples/HelloHome.class
examples/HelloLocal.class
examples/Hello.class
Déployer le bean
Cette étape varie selon le container
Simple copie avec JBoss,
A l'aide d'un outil de déploiement spécifique (BAS…)
Lors du déploiement
Vérification du fichier.jar,
Le container génère les EJBObjects et EJBHome,
Le container génère les stubs et skeletons pour les appelsRMI-
IIOP.
Vérifier le déploiement
Le serveur doit vous avertir qu'il a bien chargé le bean.
Écriture d'un client
Deux types de clients
1. Clients JAVA RMI-IIOP : ils utilisent JNDI pour localiser
les objets et Java Transaction API pour contrôler les
transactions.
2. Clients CORBA : par exemple écrits en C++… Ils utilisent
COS Naming Service et Object Transaction Service (OTS)
pour les transactions…
Quel que soit le client
1. Localiser (lookup) un objet Home,
2. Utiliser cet objet Home pour créer (create) un EJBObject,
3. Appeler les méthodes de l'EJBObject,
4. 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. The
* EJB object will delegate the call to the bean,
* 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();
}
}