0% ont trouvé ce document utile (0 vote)
32 vues78 pages

Java : Fonctions Avancées et Multitâche

Le document présente un cours avancé sur le langage Java, abordant des concepts tels que les flux, les threads, la programmation réseau et l'accès aux bases de données via JDBC. Il détaille les classes et méthodes essentielles pour la manipulation des fichiers et des données, ainsi que la gestion des exceptions. Le cours est structuré en plusieurs chapitres, chacun traitant d'un aspect spécifique de la programmation Java.

Transféré par

Ab Ir
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
32 vues78 pages

Java : Fonctions Avancées et Multitâche

Le document présente un cours avancé sur le langage Java, abordant des concepts tels que les flux, les threads, la programmation réseau et l'accès aux bases de données via JDBC. Il détaille les classes et méthodes essentielles pour la manipulation des fichiers et des données, ainsi que la gestion des exceptions. Le cours est structuré en plusieurs chapitres, chacun traitant d'un aspect spécifique de la programmation Java.

Transféré par

Ab Ir
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Lycée polyvalent DIDEROT Département IRIS

61, rue David d’Angers


75019 PARIS
http://www.diderot.org

COURS
Java – Notions avancées
Description courte
Auteur Version - Date Nom du fichier
G.VALET Version 2.4 - Mai 2003 Cours N°3 - Fonctions avancées JAVA - IRIS.docx
Apprentissage des notions avancées du langage : Les flux, les threads, les bases de données, la programmation
réseau
COURS Java – Notions avancées

A. Sommaire
A. SOMMAIRE .............................................................................................................................................................. 2
CHAPITRE 1 : ACCES AUX FLUX ET AUX FICHIERS ................................................................................................... 5
A. INTRODUCTION ......................................................................................................................................................... 5
B. LES CLASSES INPUTSTREAM, OUTPUTSTREAM ................................................................................................................. 5
B.1. Modèle objet ................................................................................................................................................ 5
B.2. Ecriture et lecture ......................................................................................................................................... 6
B.3. Lire/Ecrire dans des fichiers .......................................................................................................................... 7
B.4. Lire/Ecrire des données numériques ............................................................................................................. 7
B.5. Chaînage des flux filtrés ............................................................................................................................... 8
C. LES CLASSES READER ET WRITER ................................................................................................................................... 9
C.1. Flux de caractères ......................................................................................................................................... 9
C.2. Saisie de caractères au clavier .................................................................................................................... 10
C.3. Types de codage de caractères ................................................................................................................... 10
C.4. Fichiers ........................................................................................................................................................ 10
C.5. Flux de sortie de texte ................................................................................................................................. 10
C.6. Flux d'entrée de texte ................................................................................................................................. 11
D. LES EXCEPTIONS ...................................................................................................................................................... 11
D.1. Lecture dans un fichier ............................................................................................................................... 11
D.2. Ecriture dans un fichier ............................................................................................................................... 12
E. LES FICHIERS ZIP ..................................................................................................................................................... 14
E.1. Principe de lecture ...................................................................................................................................... 14
E.2. Exemple complet......................................................................................................................................... 15
E.3. Principe d'écriture ....................................................................................................................................... 17
CHAPITRE 2 : PROGRAMMATION MULTITACHES AVEC LES THREADS ...................................................................17
A. INTRODUCTION ....................................................................................................................................................... 17
A.1. Programmation multitâche ........................................................................................................................ 17
A.2. Threads et processus .................................................................................................................................. 18
A.3. Le "faux multitâche" ................................................................................................................................... 18
B. UTILISER LES THREADS .............................................................................................................................................. 18
B.1. Qu'est-ce qu'un thread ............................................................................................................................... 18
B.2. Un exemple de thread ................................................................................................................................ 18
B.3. L'objet thread ............................................................................................................................................. 19
B.4. Exécution de plusieurs threads ................................................................................................................... 21
C. PROPRIETES DES THREADS ......................................................................................................................................... 21
C.1. Etats des threads ........................................................................................................................................ 21
C.2. Thread bloqué ............................................................................................................................................. 21
C.3. Thread mort (Deadlock) .............................................................................................................................. 22
C.4. Interrompre un thread ................................................................................................................................ 22
C.5. Priorités d'un thread ................................................................................................................................... 23
C.6. Threads égoïstes ......................................................................................................................................... 23
C.7. Constructeurs et méthodes de la classe Thread ......................................................................................... 23
D. EXEMPLE COMPLET .................................................................................................................................................. 26
D.1. Présentation ............................................................................................................................................... 26
D.2. Code source ................................................................................................................................................ 27
E. GROUPES DE THREADS .............................................................................................................................................. 30
E.1. Construire un groupe de threads ................................................................................................................ 31
E.2. Interrompre les threads d'un groupe .......................................................................................................... 31
E.3. Connaître les threads actifs ........................................................................................................................ 31
F. SYNCHRONISATION................................................................................................................................................... 32
F.1. Présentation du problème .......................................................................................................................... 32
F.2. mot clé synchronised .................................................................................................................................. 32
COURS Java – Notions avancées

F.3. Verrous d'objets .......................................................................................................................................... 33


F.4. wait et notify ............................................................................................................................................... 33
wait ..................................................................................................................................................................................33
notify et notifyAll .............................................................................................................................................................33
G. LES THREADS ET SWING .......................................................................................................................................... 34
G.1. Quand utiliser les threads ? ........................................................................................................................ 34
CHAPITRE 3 : PROGRAMMATION RESEAU ............................................................................................................35
A. INTRODUCTION ....................................................................................................................................................... 35
A.1. Modèle OSI ................................................................................................................................................. 35
A.2. Protocoles ................................................................................................................................................... 35
A.3. Où travaille Java ......................................................................................................................................... 36
B. IMPLEMENTER DES SOCKETS....................................................................................................................................... 37
B.1. Introduction ................................................................................................................................................ 37
B.2. Classe Socket .............................................................................................................................................. 37
Créer des sockets.............................................................................................................................................................37
Lire et écrire des données ...............................................................................................................................................38
Temps d'attente ..............................................................................................................................................................39
Socket et Thread ..............................................................................................................................................................39
B.3. Classe InetAddress ...................................................................................................................................... 40
B.4. Exemple de connexion à un serveur ........................................................................................................... 42
C. IMPLEMENTER UN SERVEUR ....................................................................................................................................... 43
C.1. Types de serveurs........................................................................................................................................ 43
C.2. Classe ServerSocket .................................................................................................................................... 44
Exemple d'un serveur mono-client..................................................................................................................................44
Exemple d'un serveur multi-clients .................................................................................................................................46
D. CONNEXION A DES SERVEURS HTTP ............................................................................................................................. 48
D.1. Classe URL .................................................................................................................................................. 48
Composition d'une URL ...................................................................................................................................................48
Méthode openConnection ..............................................................................................................................................48
Méthode openStream .....................................................................................................................................................48
D.2. Classe URLConnection ................................................................................................................................ 49
Instanciation ....................................................................................................................................................................49
setDoInput et setDoOutput .............................................................................................................................................49
Méthode setIfModifiedSince ...........................................................................................................................................49
Méthode setUseCaches ...................................................................................................................................................49
Méthode connect ............................................................................................................................................................49
Méthode getHeaderFieldKey...........................................................................................................................................50
D.3. Lire les données provenant de serveurs ..................................................................................................... 51
D.4. Ecrire des données vers un serveur ............................................................................................................ 51
Méthode GET...................................................................................................................................................................51
Méthode POST ................................................................................................................................................................52
Ecrire des données ..........................................................................................................................................................52
D.5. Classe URLEncoder ..................................................................................................................................... 53
D.6. Classe URLDecoder ..................................................................................................................................... 53
CHAPITRE 4 : BASES DE DONNEES AVEC JDBC ......................................................................................................54
A. INTRODUCTION ....................................................................................................................................................... 54
B. PRESENTATION ....................................................................................................................................................... 55
B.1. Schéma ....................................................................................................................................................... 55
B.2. Le gestionnaire de pilotes (JDBC Driver Manager) ..................................................................................... 55
B.3. Les pilotes ................................................................................................................................................... 55
Pilote de type I.................................................................................................................................................................56
Pilote de type II................................................................................................................................................................56
Pilote de type III...............................................................................................................................................................56
Pilote de type IV ..............................................................................................................................................................56
C. MISE EN ŒUVRE DE JDBC ......................................................................................................................................... 57
C.1. Introduction ................................................................................................................................................ 57
C.2. Se procurer un pilote................................................................................................................................... 57
C.3. Importer le package nécessaire .................................................................................................................. 57
COURS Java – Notions avancées

C.4. Enregistrer le pilote .................................................................................................................................... 58


C.5. Etablir la connexion à la base de données .................................................................................................. 58
URL de connexion ............................................................................................................................................................58
Méthode getConnection .................................................................................................................................................59
C.6. Créer une zone de description de requête (Statement) .............................................................................. 59
C.7. Exécuter une requête .................................................................................................................................. 60
C.8. Lire des données dans un ResultSet ............................................................................................................ 61
D. LE TRAITEMENT DES EXCEPTIONS ................................................................................................................................ 63
E. CARACTERISTIQUES D'UN RESULTSET ........................................................................................................................... 64
E.1. ResultSet de type FORWARD_ONLY ............................................................................................................ 64
E.2. ResultSet de type TYPE_SCROLL_INSENSITIVE ............................................................................................ 64
E.3. ResultSet de type TYPE_SCROLL_SENSITIVE ............................................................................................... 64
E.4. Modifier des enregistrements ..................................................................................................................... 65
F. PARCOURIR UN RESULTSET ........................................................................................................................................ 66
F.1. Les méthodes .............................................................................................................................................. 66
F.2. Exemple....................................................................................................................................................... 67
G. INSERER ET MODIFIER UN RESULTSET .......................................................................................................................... 67
G.1. Insérer ........................................................................................................................................................ 67
G.2. Modifier ...................................................................................................................................................... 68
H. UTILISATION DE REQUETES PRE-COMPILEES .................................................................................................................. 68
H.1. Introduction ................................................................................................................................................ 68
H.2. Comment créer un objet PreparedStatement ?.......................................................................................... 68
H.3. Exécuter avec des paramètres ................................................................................................................... 69
H.4. Exécuter au sein d’une boucle .................................................................................................................... 69
I. LES META-DONNEES .................................................................................................................................................. 70
I.1. Introduction ................................................................................................................................................. 70
I.2. DatabaseMetaData ..................................................................................................................................... 70
I.3. ResultSetMetaData...................................................................................................................................... 71
J. TRANSACTIONS AVEC JDBC ........................................................................................................................................ 73
J.1. Introduction ................................................................................................................................................. 73
J.2. Le mode « auto-commit » ........................................................................................................................... 73
J.3. Annuler une transaction .............................................................................................................................. 74
J.4. Niveaux de transactions .............................................................................................................................. 74
COURS Java – Notions avancées

Chapitre 1 : Accès aux flux et aux fichiers


A. Introduction
Les flux sont en matière de programmation, des objets chargés de contrôler l'envoi et la
réception de données à travers un périphérique du système ou en dehors du système. La
relation entre les flux et les entrées/sorties est très forte et le modèle objet est très fourni.
Les classes InputStream et OutputStream sont utilisées pour la réception et l’envoi d'octets
alors que les classes Reader et Writer sont utilisées pour les caractères (ANSI1).
Quelque soit le type de flux, étant donné que la disponibilité d'un périphérique ne dépend pas
du système exécutant le programme, la gestion des exceptions est indispensable et fait partie
intégrante de la gestion des flux. En effet, si un flux vers une imprimante est envoyé, il faut
anticiper sur la réaction de vos programmes si l'imprimante n'est pas connectée ou s'il lui
manque du papier.

B. Les classes InputStream, OutputStream


B.1. Modèle objet
Ce sont des classes abstraites qui n'ont d'intérêt que si elles sont dérivées par des classes plus
puissantes capables d'envoyer et de recevoir vers un périphérique donné. Par exemple, la
classe FileInputStream sera capable de lire des octets dans un fichier.
Les classes descendantes de InputStream et OutputStream sont très nombreuses, ce qui permet
de faire face à des situations très diverses , telles que :
 La lecture/écriture bufferisée grâce à BufferedInputStream
 La lecture/écriture de fichiers compressés zip, gzip grâce à GZIPInputStream ou
ZIPInputStream.
 L'impression grâce à PrintStream
 …

Le modèle objet est donné dans la figure 1 de la page suivante.

1
ANSI : Norme de codage des caractères sur 2 octets
COURS Java – Notions avancées

Fig 1 : Hiérarchie des flux d'octets

B.2. Ecriture et lecture


Les classes OutputStream et InputStream possèdent des méthodes abstraites qui peuvent être
surchargées dans les classes enfant. Ces méthodes renvoient des exceptions qui devront être
traitées par l'utilisateur.

Voici par exemple la signature de la méthode read de la classe InputStream :


COURS Java – Notions avancées

public abstract int read() throws IOException

Voici un autre exemple de la méthode write de la classe OutputStream :


public abstract void write(int b) throws IOException

La lecture ou l'écriture peut également se faire par ensemble d'octets à l'aide des tableaux. Les
méthodes read et write ne sont plus abstraites :
public void write( byte[] b) throws IOException
ou
public int read( byte [] b ) throws IOException

B.3. Lire/Ecrire dans des fichiers


La classe FileInputStream , dérivée de InputStream permet d'effectuer une lecture d'octets dans
un fichier. Associée à un objet de type File , le flux correspond alors à un flux de fichier :
File f = new File("fiche.dat")
FileInputStream fl = new FileInputStream(f);
La lecture d'un octet se fait alors avec la méthode read :
byte b=fl.read();

B.4. Lire/Ecrire des données numériques


La classe DataInputStream permet de lire des données de type numériques tels que les
flottants, les booléens, les octets ou les entiers (type double, boolean, byte et int). Voici un
aperçu partiel des méthodes de la classe DataInputStream disponibles :

Méthodes de DataInputStream (Non exhaustif)


int read(byte[] b)
Lit l'ensemble des octets du flux et les stocke dans un tableau.
Renvoie –1 si la fin du flux a été atteinte.
int read(byte[] b, int off, int len)
Lit le flux à partir de off sur len octets. Renvoie –1 si la fin du flux est
atteinte
boolean readBoolean()
Renvoie un booléen égal à true si l'octet lu est non nul et false si
l'octet est nul
byte readByte()
Renvoie l'octet lu.
char readChar()
Renvoie le caractère correspondant à l'octet lu
double readDouble()
Lit 8 octets et renvoie le double correspondant.
COURS Java – Notions avancées

B.5. Chaînage des flux filtrés


Vous avez remarqué que DataInputStream ne sait lire que des types numériques mais que
FileInputStream ne dispose pas des méthodes nécessaires pour lire des données de type
numériques. La question est de savoir comment lire des données de type numériques dans des
fichiers ?
La réponse est le chaînage des flux filtrés dont est le principe est d'utiliser plusieurs types de
flux en enchaînant leur construction. Voilà un exemple de code permettant de lire des données
numériques dans un fichier :
FileInputStream fis = new FileInputStream("fiche.dat");
DataInputStream dis = new DataInputStream(fis);

double s = dis.readDouble();
Cet enchaînement va vous permettre d'associer les différents types de flux de manière à
bénéficier de leurs fonctionnalités. En effet, partons du principe que DataInputStream sait lire
des numériques et FileInputStream sait lire dans des fichiers et associons les pour qu'ils nous
fassent partager leurs compétences propres.
Dans notre exemple, si nous souhaitons qu'en plus de lire des données numériques dans des
fichiers, nous souhaitions que cette lecture soit bufferisée2 , il suffirait d'associer à nos 2 objets
précédent, un 3ème issu de la classe BufferedInputStream . L'exemple suivant nous montre
l'enchaînement de la construction :
DataInputStream dis = new DataInputStream
(new BufferedInputStream
( new FileInputStream("fiche.dat") ));
L'objet de type DataInputStream est en haut de la chaîne de flux puisque ses méthodes d'accès
aux données nous serons utiles pour lire des données de type numériques.
La méthode read() de l'objet dis va procéder à une lecture bufferisée dans le flux.
Cette syntaxe n'est pas très conviviale mais l'empilement des constructeurs est un passage obligé
pour arriver à obtenir un flux avec de telles fonctionnalités.
Pour finir, voici un dernier exemple permettant de lire un booléen dans un fichier ZIP:
ZipInputStream zis = new ZipInputStream(
new FileInputStream("fiche.zip") );
DataInputStream dis = new DataInputStream(zis);
Pour lire un booléen dans ce fichier ZIP, on utilise :
boolean b = dis.readBoolean();

2
bufferiser : Action de lire un ensemble de données simultanément dans un flux et de les stocker temporairement
jusqu'à leur traitement. L'avantage est que l'accession aux données ne s'effectue qu'une seule fois par opposition à
une lecture non bufferisée où la lecture de chaque élément nécessite un accès dédié et coûteux en mémoire.
COURS Java – Notions avancées

C. Les classes Reader et Writer


Nous avons vu l'écriture de fichiers binaires avec les classes InputStream et OutputStream. Il est
temps de voir comment utiliser les classes Reader et Writer pour écrire des flux de caractères.
Le système de flux filtrés va servir à créer des flux spécifiques.
Voici le modèle objet des classes Reader et Writer :

Hiérarchie des flux de caractères

C.1. Flux de caractères


Java propose de coder les caractères selon la norme UNICODE3. Chaque plate-forme
d'exécution ayant une manière différente de coder les caractères , JAVA met tout le monde
d'accord en proposant un mécanisme de flux filtrés. Ces classes, issues de Reader et de Writer,
vont s'adapter à l'environnement d'exécution et effectuer un codage à base d'UNICODE. La
classe InputStreamReader , par exemple, transforme un flux d'entrée en octets, en un flux
émettant des caractères UNICODE.

3
UNICODE : Système de codage sur 16 bits des caractères opposé à la norme ANSI sur 8 bits
COURS Java – Notions avancées

C.2. Saisie de caractères au clavier


L'API Java propose une classe System permettant d'agir avec les propriétés du système hôte. Le
champ statique in de type InputStream , permet de renvoyer des octets correspondant aux
caractères tapés au clavier. Il peut être utile de transformer ce flux en un flux de caractères
UNICODE par le truchement des flux filtrés :
InputStreamReader fluxUnicode = new InputStreamReader(System.in);

C.3. Types de codage de caractères


Chaque machine hôte peut avoir un jeu de caractères différent selon son pays d'origine. Sans
parler pour l'instant d'internationalisation, il est possible de créer des objets de type
InputStreamReader avec un jeu spécifique :
fluxUnicode = new InputStreamReader(System.in , "8859_5");
La chaîne de caractères passé en argument du constructeur correspond au jeu de caractère
Latin/Cyrillique ISO. Voici quelques exemples de jeu de caractères :

Jeux de caractères (Non exhaustif)


8859_1 Latin-1 ISO (jeu par défaut sous Windows)
Cp865 Langues nordiques pour PC
Cp949 Coréen pour PC
MacGreek Grec pour Macintosh
Cp850 Latin-1 pour PC
Cp280 Italien pour IBM

C.4. Fichiers
Il existe un type particulier pour lire et écrire dans des fichiers. Il s'agit des classes FileWriter et
FileReader. Ces sont en fait un objet de type OutputStreamWriter associé à un objet de type
FileOutputStream. Les deux programmes suivant sont identiques :
FileWriter fw = new FileWriter("data.txt");
ou
OutputStreamWriter fw = new OutputStreamWriter(
new FileOutputStream("data.txt") ) ;

Les classes FileWriter et FileReader sont des classes d'aide permettant d'obtenir un flux de
caractères facilement.

C.5. Flux de sortie de texte


La classe PrintWriter est très utile pour envoyer des caractères vers une destination quelconque
(Un fichier, une imprimante). Les objets issus de cette classe sont associés avec un objet
indiquant la destination :
PrintWriter pw = new PrintWriter(new FileWriter("data.txt"));
COURS Java – Notions avancées

L'intérêt du code précédent est de pouvoir disposer de toutes les méthodes telles que print,
println , tout comme l'objet System.out. Ces méthodes permettent d'envoyer tout type de
données primitifs tels que int, char, String ..
Selon les systèmes hôtes, les caractères de fin de lignes varient ( \r\n pour Windows , \n pour
UNIX, \r pour Macintosh. Pour résoudre ce problème, JAVA propose un appel à la méthode
System.getProperty("line.separator") qui renvoie les caractères correspondant à la plate-forme
d'exécution

C.6. Flux d'entrée de texte


JAVA ne proposant pas l'équivalent de PrintWriter en entrée, il ne nous reste plus qu'à utiliser
un objet de type BufferedReader associé à l'objet destination :
BufferedReader br = new BufferedReader(new FileReader("toto.txt"));
La méthode readline permet de lire ligne par ligne le flux d'entrée. Lorsque la fin du fichier est
atteinte, cette méthode renvoie null :
String ligne;
while ( ( s= br.readLine()) != null)
{
… Traitement de lecture
}

Pour lire autre chose que des caractères, il faut convertir les caractères obtenus grâce aux
méthodes de conversion des objets :
String s = br.readline();
double x = Double.parseDouble(s);
La méthode statique parseDouble permet de convertir une chaîne en un Double.

D. Les exceptions
Bien entendu, comme la lecture ou l'écriture dans un flux n'est jamais sûre, les objets
permettant l'accès à ces flux respectent le mécanisme des exceptions, au cas où la lecture ou
l'écriture échouerait.

D.1. Lecture dans un fichier


L'exemple suivant montre comment lever une exception pour la lecture caractère par caractère
dans fichier :
String fileString = "";
FileReader fr ;
try {
fr = new FileReader("data.txt");
int i=0;
while ( (i = fr.read()) != -1 )
fileString += (char) i;
fr.close();

} catch ( FileNotFoundException fe ) {
System.out.println("Fichier introuvable");
COURS Java – Notions avancées

} catch (IOException e) {
System.out.println("Erreur d'E/S");
}
La méthode read de l'objet FileReader renvoie –1 si la fin du fichier est atteinte. La chaîne
fileString contient alors l'ensemble du fichier. Vous remarquerez que la méthode read renvoie
un entier qu'il faut convertir en caractère pour le traiter.
Les exceptions levées sont de type IOException et FileNotFoundException. Elles correspondent
aux erreurs courantes se produisant au niveau des fichiers.

D.2. Ecriture dans un fichier


Voici le même exemple pour l'écriture :
FileWriter fw ;
String chaine = "Chaine a ecrire " ;
try {
fw = new FileWriter("data.txt");

for (int i=0 ; i< chaine.length() ; i++)


fw.write(chaine.substring(i,i+1));
fw.close();
} catch ( FileNotFoundException fe ) {
System.out.println("Fichier introuvable");
throw fe;

} catch (IOException e) {
System.out.println("Erreur d'E/S");
}

Vous noterez que les mêmes exceptions sont levées pour l'écriture.

Le répertoire utilisé pour lire et écrire dans des fichiers si aucun chemin n'est spécifié, est le
répertoire courant correspondant au répertoire d'où le programme a été exécuté. Pour obtenir le
chemin complet, vous pouvez faire appel à la méthode statique getProperty("user.dir") de la
classe System. Attention cependant à cette méthode qui peut envoyer des exceptions si la
propriété n'existe pas ou encore si la sécurité est activée et empêche le programme d'accéder à
ces propriétés.

La plupart du temps, la classe chargée d'ouvrir les fichiers et la classe chargée d'informer
l'utilisateur en cas d'échec n'étant pas la même, il devient indispensable de renvoyer les
exceptions au code appelant :

try {
fw = new FileWriter("data.txt");
int i=0;
for (int i=0 ; i< chaine.length() ; i++)
fw.write(chaine.substring(i,i+1));
fw.close();
} catch ( FileNotFoundException fe ) {
System.out.println("Fichier introuvable");
throw fe;
} catch (IOException e) {
System.out.println("Erreur d'E/S");
COURS Java – Notions avancées

throw e;
}
COURS Java – Notions avancées

E. Les fichiers ZIP


Les fichiers compressés sont très utilisés dans le monde de l'internet et JAVA , en tant que
langage évolué se devait de couvrir cet aspect. JAVA reconnaît les format de type ZIP et GZIP (
Normes RFC 1950 , RFC 1951 et RFC 1952)4.
Le format ZIP le plus couramment utilisé sera traité ici, sachant que le format GZIP fonctionne
de manière semblable.
Les classes utilisées pour traiter les fichier ZIP sont situées dans le package java.util.zip.
N'oubliez d'ajouter ce package grâce à une instruction import appropriée.

E.1. Principe de lecture


Un fichier ZIP possède un en-tête comprenant des informations sur le nom du fichier et la
méthode de compression utilisée. La classe JAVA ZipInputStream associée à la classe
FileInputStream nous permettra d'accéder à chaque entrée individuelle par l'intermédiaire de la
classe ZipEntry.
La méthode read de ZipInputStream renvoie –1 dès que la fin de l'entrée est rencontrée.
Lorsqu'une entrée à été lue, il est indispensable d'appeler la méthode closeEntry avant de passer
à l'entrée suivante.
Voici un exemple de lecture dans un fichier zip :
ZipInputStream zin = new ZipInputStream (
new FileInputStream(zipname));
ZipEntry entry;

while ((entry=zin.getNextEntry()) != null)


{
.. Lecture du contenu de l'entrée
zin.closeEntry();
}
zin.Close();

Pour lire dans une entrée, vous éviterez de vous servir de la méthode read qui ne fourni aucun
formatage. Les méthodes spécifiques d'un flux filtré seront plus apropriées. Par exemple, pour
lire un fichier texte se trouvant dans un fichier ZIP :
BufferedReader in = new BufferedReader(
new InputStreamReader(zin));
String s;
while (( s= in.readline()) != null )
… Traitement de la ligne

4
RFC : Request For Comment , groupes de travail précisant les normes de tous les protocoles et langages
concernant l'informatique.
COURS Java – Notions avancées

E.2. Exemple complet


L'exemple complet suivant permet d'ouvrir un fichier ZIP et d'afficher le contenu de chaque
entrée dans la fenêtre.
/**
* @version 1.20 17 Aug 1998
* @author Cay Horstmann
*/

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;

public class ZipTest extends JFrame


implements ActionListener
{ public ZipTest()
{ setTitle("ZipTest");
setSize(300, 400);

JMenuBar mbar = new JMenuBar();


JMenu m = new JMenu("File");
openItem = new JMenuItem("Open");
openItem.addActionListener(this);
m.add(openItem);
exitItem = new JMenuItem("Exit");
exitItem.addActionListener(this);
m.add(exitItem);
mbar.add(m);

fileList.addActionListener(this);

Container contentPane = getContentPane();


contentPane.add(mbar, "North");
contentPane.add(fileList, "South");
contentPane.add(fileText, "Center");
}

public void actionPerformed(ActionEvent evt)


{ Object source = evt.getSource();
if (source == openItem)
{ JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("."));
chooser.setFileFilter(new FileFilter()
{ public boolean accept(File f)
{ return f.getName().toLowerCase()
.endsWith(".zip")
|| f.isDirectory();
}
public String getDescription()
{ return "ZIP Files"; }
});
int r = chooser.showOpenDialog(this);
if (r == JFileChooser.APPROVE_OPTION)
{ zipname = chooser.getSelectedFile().getPath();
COURS Java – Notions avancées

scanZipFile();
}
}
else if (source == exitItem) System.exit(0);
else if (source == fileList)
loadZipFile((String)fileList.getSelectedItem());
}

1 public void scanZipFile()


2 { fileList.removeAllItems();
3 try
4 { ZipInputStream zin = new ZipInputStream(new
5 FileInputStream(zipname));
6 ZipEntry entry;
7 while ((entry = zin.getNextEntry()) != null)
8 { fileList.addItem(entry.getName());
9 zin.closeEntry();
10 }
11 zin.close();
12 }
13 catch(IOException e) {}
14 }

15 public void loadZipFile(String name)


16 { try
17 { ZipInputStream zin = new ZipInputStream(new
18 FileInputStream(zipname));
19 ZipEntry entry;
20 fileText.setText("");
21 while ((entry = zin.getNextEntry()) != null)
22 { if (entry.getName().equals(name))
23 { BufferedReader in = new BufferedReader(new
24 InputStreamReader(zin));
25 String s;
26 while ((s = in.readLine()) != null)
27 fileText.append(s + "\n");
28 }
29 zin.closeEntry();
30 }
31 zin.close();
32 }
33 catch(IOException e) {}
34 }

public static void main(String[] args)


{ Frame f = new ZipTest();
f.show();
}

private JComboBox fileList = new JComboBox();


private JTextArea fileText = new JTextArea();
private JMenuItem openItem;
private JMenuItem exitItem;
private String zipname;
}

 63-76 : Parcours du fichier ZIP (Lecture) à partir d'un flux filtré composé d'un
ZipInputStream et d'un FileInputStream.
 78-97 : Lecture de l'entrée avec le même flux filtré mais pour chaque entrée,
utilisation d'un autre flux filtré composé d'un BufferedReader et d'un
COURS Java – Notions avancées

InputStreamReader. La boucle s'arrête lorsque la fin du flux est atteinte et que la


méthode readLine renvoie null.

E.3. Principe d'écriture


Pour écrire dans un fichier ZIP, l'utilisation d'un flux de type ZipOutputStream associé avec un
flux de type FileOutputStream semble le plus approprié. Un objet de type ZipEntry sera crée
pour chaque nouvelle entrée dans le fichier. Il suffit de passer au constructeur de ZipEntry le
nom du fichier , qui déterminera la date de création et le mode de décompression par défaut. Il
vous faudra ensuite appeler la méthode putNextEntry du flux ZipOutputStream pour
commencer à écrire :
FileOutputStream fout = new FileOutputStream ("data.zip");
ZipOutputStream zout = new ZipOutputStream(fout);
et la boucle à effectuer pour chaque nouvelle entrée :
{
ZipEntry ze = new ZipEntry(filename);
zout.putNextEntry(ze);
…Envoyer les données à ze
zout.closeEntry();
}

Chapitre 2 : Programmation multitâches avec les Threads


A. Introduction
A.1. Programmation multitâche
Tous les systèmes d'exploitation actuels ont la possibilité d'effectuer plusieurs tâches en
simultané. Toute l'informatique d'aujourd'hui utilise ce principe essentiel à la réalisation de
tâches complexes tel que le fenêtrage sous Windows par exemple.
En effet, lorsqu'un utilisateur consulte un site Internet , l'ordinateur effectue plusieurs tâches
en même temps, comme gérer la communication Internet, analyser le contenu reçu, et gérer
l'arrivée permanente de données.
Donc, chaque processus exécuté sur la machine est plus ou moins indépendant des autres.
On distingue deux types de programmes multitâches. Le multitâche dit préemptif et le multitâche
dit coopératif. Le premier est un programme dont l'exécution est contrôlé par le système
d'exploitation qui peut choisir de le stopper à tout moment sans attendre une autorisation de sa
part. Le second peut être interrompu uniquement s'il l'autorise.
Windows NT (Windows 95 et 98 pour les programmes 32bits) un OS5 préemptif ce qui lui
confère une plus grande stabilité que les OS coopératifs. En effet, lorsqu'un programme mal
conçu se plante pendant son exécution, un appui sur les touches CTRL-ALT-SUPPR suffit à
récupérer la main pour stopper le programme incriminé.

5
OS : Operating System – Système d'exploitation
COURS Java – Notions avancées

A.2. Threads et processus


Il existe une différence entre les threads et les processus. Un processus est un programme
s'exécutant de manière indépendante des autres processus. Il possède une copie unique de ses
propres variables. Le thread, lui, partage les données avec les autres threads. Cela peut paraître
dangereux dans un premier temps mais il s'avère que cette possibilité les rend plus rapides et
plus faciles à gérer que les processus. En effet, il est bien plus rapide de créer et de détruire les
threads individuels que de créer des processus.
Dans les G.U.I6, la gestion des évènements s'exécute dans un thread différent de l'application, ce
qui permet à ces applications de réagir instantanément ou presque aux actions de l'utilisateur,
tout en continuant le traitement des données.

A.3. Le "faux multitâche"


La plupart des ordinateurs n'ayant qu'un seul processeur, le système utilise un mécanisme
astucieux faisant croire à l'utilisateur qu'il réalise plusieurs choses en même temps. En effet,
chaque thread dispose d'un temps de parole (temps minimal pendant lequel il va s'exécuter)
après lequel il doit rendre la main au système pour laisser une chance aux autres threads de
faire leur travail.
Voilà pourquoi on peut parler de "faux multitâche"

B. Utiliser les threads


B.1. Qu'est-ce qu'un thread
Il s'agit d'un programme s'exécutant en même temps que d'autres programmes. Il est capable
de se mettre en sommeil pour permettre aux autres threads d'avoir une chance d'être exécuté.
La période de sommeil est fixée par lui et le programmeur aura à charge de donner une valeur
raisonnable de ce temps, pour permettre aux autres threads de pouvoir s'exécuter.
Dans un environnement multitâche préemptif, même si le thread a un temps de sommeil fixé par
avance, cela n'empêchera l'OS d'interrompre le programme quand bon lui semblera pour
effectuer d'autres tâches. Sur un ordinateur dont la performance est en adéquation avec les
exigences minimales du système d'exploitation, le programme multi-thread fonctionnera de
manière transparente pour l'utilisateur

B.2. Un exemple de thread


Le navigateur qui nous sert à consulter des sites Web dispose d'une fonctionnalité intéressante
qui consiste à télécharger plusieurs images d'une page en même temps. Le téléchargement et
l'affichage d'une image correspond à un thread distinct. Le navigateur peut choisir de démarrer
plusieurs téléchargements simultanés et cela , en rapport avec le débit maximum de la
connexion.

6
GUI : Graphic User Interface – Interface graphique utilisateur
COURS Java – Notions avancées

ad N °1 page.htm l
T h re
T éléch argem en t
A fficha ge

im g 1.jp g

ad N °2
T h re
T éléch argem en t
A fficha ge

a d N °3
im g 2.jp g T hre
T éléch argem en t
A fficha ge

im g 3.jp g

Exemple d'utilisation des Threads

B.3. L'objet thread


Tout d'abord, lorsqu'on souhaite qu'une classe puisse se comporter comme un thread , il faut
que :
 Cette classe implémente l'interface Runnable , surcharge la méthode run et
contient un champ de type Thread.
ou que :
 Cette classe hérite de la classe Thread.

La deuxième solution s'avère irréaliste étant donné que la plupart du temps, vos propres classes
hériteront déjà d'une autre classe et par conséquent, ne pourront pas hériter de plusieurs classes.
En JAVA, l'héritage multiple n'est pas supporté. Néanmoins, si votre classe n'hérite d'aucune
autre, il est préférable de la faire hériter de la classe Thread
Voici un diagramme objet représentant le cas de figure le plus courant où l'objet devant
s'exécuter comme un thread implémente l'interface Runnable et hérite de sa classe parent.
COURS Java – Notions avancées

Diagramme objet pour les threads

Le code Java pour ce modèle pourrait être le suivant :


public class ThreadedClass extends ParentClass implements Runnable {

35 // Champs
Thread th;

36 // Constructeurs
public ThreadedClass() {
th = new Thread(this); // Lie la classe avec le thread qu'elle
// contient
th.start(); // Démarre le thread

37 // Méthodes
public void run() { // Méthode appelée par start()
… Processus d'exécution
th.sleep(100); //Met le thread en sommeil pendant 100ms
}
}
Code partiel de l'utilisation d'un thread
COURS Java – Notions avancées

B.4. Exécution de plusieurs threads


L'objectif du multitâche étant d'exécuter plusieurs threads , en simultané, il faut donc une
organisation sans de manière à ce que chaque thread est une chance de s'exécuter. En tant que
développeur, cette responsabilité vous incombe puisque vous allez pouvoir fixer le temps de
sommeil de vos threads.
Voici un schéma illustrant le processus d'exécution des threads sur une machine disposant d'un
seul processeur :

Thread s’exécutant Thread en som m eil

Thread 1 Thread 1
Thread 2 Thread 2
Thread 3

Exécution de plusieurs thread sur une machine mono processeur

C. Propriétés des threads


C.1. Etats des threads
Les threads peuvent être dans plusieurs états différents :
 Nouveau : Le thread a été crée avec new mais n'est pas encore activé
 Exécutable : La méthode start a été appelée mais cela ne signifie pas que le
thread est exécuté. Cela va dépendre du système d'exploitation qui doit lui donner
une fenêtre d'exécution.
 Bloqué : Plusieurs évènements peuvent bloquer un thread. La méthode sleep
lorsqu'elle est appelée, met le thread dans cet état. Il y a cependant plusieurs
autres causes dont nous parlerons un peu plus loin dans ce chapitre.
 Mort : Lorsque la méthode run est terminée, le thread est considéré comme mort.
Il peut y avoir d'autres causes dont nous parlerons plus loin.

C.2. Thread bloqué


Le thread peut être dans cet état pour les causes suivantes :
 La méthode sleep ou yield du thread est appelée
 Le thread appelle une opération bloquante sur les entrées-sorties. Cette opération
ne rendant pas la main tant qu'elle n'est pas terminée.
 Le thread appelle la méthode wait
 Le thread essaie de verrouiller un objet déjà verrouillé par un autre thread.
 La méthode suspend du thread est appelée (Pas conseillée !!!)
COURS Java – Notions avancées

Un thread bloqué peut uniquement être activé par la même technique que celle qui l'a bloqué.
Par exemple, un thread bloqué par une opération d'entrée-sortie devra attendre que celle-ci se
termine. De même qu'un thread bloqué par la méthode sleep devra attendre le délai passé en
argument.

C.3. Thread mort (Deadlock)


Voici les différentes raisons qui peuvent faire mourir un thread :
 Le thread meurt d'une mort naturelle parce que sa méthode run s'est terminée
 Le thread meurt soudainement parce qu'une exception non récupérée a mis fin à
la méthode run
Pour connaître l'état d'existence d'un thread , il suffit d'appeler sa méthode isAlive qui renvoie
false dans le cas où le thread est mort.

C.4. Interrompre un thread


Un thread ne s'arrête que si sa méthode run se termine. Il n'existe aucune technique intégrée à
Java pour interrompre un thread . Celui-ci doit donc vérifier régulièrement, au sein de la
méthode run, s'il doit s'arrêter :
public void run {
while ( aucune requête de fin && encore du travail à faire)
{ Travail à faire
}
}
Néanmoins, lorsque qu'un thread est endormi, il ne peut pas vérifier s'il doit s'arrêter. Voilà
tout l'intérêt de la méthode interrupt(). Lorsque cette méthode est appelée, l'exception
InterruptException termine la phase de blocage.
Un thread susceptible d'être interrompu doit donc lever l'exception InterruptException :
public void run {

try {
while ( aucune requête de fin && encore du travail à faire)
{ Travail à faire
}
} catch ( InterruptedException )
{ // Le thread a été interrompu pendant sleep ou wait
}
}

Si la méthode interrupt a été appelée pendant que le thread n'était pas bloqué, aucune
exception de type InterruptException n'est générée. Le thread doit alors appeler la
méthode interrupted pour déterminer s'il a été interrompu.

Voici la structure correcte d'un thread :


public void run {

try {
while ( encore du travail à faire && !interrupted())
{ Travail à faire }
COURS Java – Notions avancées

} catch ( InterruptedException )
{ // Le thread a été interrompu pendant sleep ou wait }
}

C.5. Priorités d'un thread


Il existe 10 niveaux de priorité d'un thread en JAVA. Voici les constantes statiques de la classe
Thread :
 MIN_PRIORITY : Valeur entière de 1
 NORM_PRIORITY : Valeur entière de 5
 MAX_PRIORITY : Valeur entière de 10
Lorsque le gestionnaire des threads doit choisir un nouveau thread a exécuter, il choisit la
plupart du temps le thread ayant la priorité la plus haute.
Un thread peut aussi être interrompu si un thread de priorité supérieure s'est réveillé

Si plusieurs thread exécutables ont la même priorité, c'est au système de gestion des
threads de décider lequel de ces threads va être exécuté. Le problème est que, d'un
système à l'autre, ce choix peut-être différent. Voici une des faiblesses du langage JAVA
qui signifie qu'on ne peut pas être sûr que les programmes multithread s'exécuteront de
la même façon sur toutes les plate formes.

C.6. Threads égoïstes


Un thread égoïste est un thread qui ne fait pas appel à sleep ou yield. Par conséquent, il ne
laisse pas la chance aux autres threads de pouvoir s'exécuter. Néanmoins, dans le cas d'un
système multitâche préemptif, c'est le système d'exploitation qui est responsable de
l'exécution des threads. Le bon fonctionnement du programme dépendra alors de l'OS.

C.7. Constructeurs et méthodes de la classe Thread

Constructeurs de Thread
Thread()
Crée un nouveau thread.
Thread(Runnable target)
Crée un nouveau Thread relatif à l'objet implémentant l'interface Runnable
Thread(Runnable target, String name)
Crée un nouveau Thread relatif à l'objet implémentant l'interface Runnable avec
un nom
Thread(String name)
Crée un nouveau Thread avec un nom
Thread(ThreadGroup group, Runnable target)
Crée un nouveau Thread relatif à l'objet implémentant l'interface Runnable ,
membre du groupe passé en argument.
COURS Java – Notions avancées

Thread(ThreadGroup group, Runnable target, String name)


Crée un nouveau Thread relatif à l'objet implémentant l'interface Runnable ,
membre du groupe passé en argument avec un nom
Thread(ThreadGroup group, String name)
Crée un nouveau Thread membre du groupe passé en argument avec un nom
Liste des constructeurs de THREAD
COURS Java – Notions avancées

Méthodes de Thread
static int activeCount()
Renvoie le nombre de threads actifs dans le groupe de ce
thread
void checkAccess()
Détermine si le thread actuellement actif a les permissions de
modifier ce thread
static Thread currentThread()
Renvoie la reference au thread actuellement exécuté
String getName()
Renvoie le nom du thread
int getPriority()
Renvoie la priorité de Thread.
ThreadGroup getThreadGroup()
Renvoie le groupe de thread auquel le thread appartient
void interrupt()
Interrompt le thread (DANGEREUX)
static boolean interrupted()
Test si le thread courant a été interrompu
boolean isAlive()
Teste si le thread n'est pas mort
boolean isInterrupted()
Test si ce thread a été interrompu
void join()
Attend que ce thread meurt.
void join(long millis)
Attends au moins millis millisecondes que ce thread meurt
void join(long millis, int nanos)
Même chose mais millis+nanos
void run()
méthode appelée par la méthode start pour démarrer le
thread
void setName(String name)
Change le nom du thread
void setPriority(int newPriority)
Change la priorité du thread
static void sleep(long millis)
Endort le thread pour une durée millis millisecondes
static void sleep(long millis, int nanos)
Endort le thread pour une durée millis millisecondes + nanos
nanonsecondes
COURS Java – Notions avancées

void start()
Démarre le thread et la machine virtuelle appelle la méthode
run
String toString()
Renvoie une représentation chaîne comportant le nom, la priorité
et le groupe auquel appartient le thread
static void yield()
Provoque l'arrêt de l'exécution du thread et autorise les autres
threads à s'exécuter
Liste non exhaustive des méthodes de la classe Thread

D. Exemple complet
D.1. Présentation
Voici l'exemple d'une fenêtre affichant un texte clignotant dès qu'on appui sur un bouton. A
chaque appui sur ce bouton, un thread différent est exécuté :

Voici le diagramme objet de cet exemple :


COURS Java – Notions avancées

ThreadFram e.java

- panel : Jpanel
- southPanel : J panel Interface
- sta rtB utton : Jbutton R unna ble
- closeB utton : Jbutton
- threadCo unt : int

+run()
initCom ponents ( ) : void
closeB uttonAc tionPerform ed(Ac tionEv ent) : void
startButtonA ctionP erform ed(A ctionE vent) : void

im plém en te
A un

- threadText : Thread
- x,y : int
- tex te : String
- panel : Jpanel

+ ThreadText(JP anel , S tring) : void


+run() : void
+draw () :void
+ getP anelS ize() : D im ension
+ getR andom P osition : D im ension

ThreadText.java
Voici le code source des fichiers ThreadText.java et ThreadFrame.java

D.2. Code source


38 /*
39 * ThreadText.java
40 *
41 * Created on 2 octobre 2001, 17:11
42 */
import javax.swing.*;
import java.awt.*;
43 /**
44 *
45 * @author genael
46 * @version
47 */
public class ThreadText implements Runnable {

48 /** Texte à afficher


49 */
private String text;

50 /** Position horizontale du texte


51 */
private int x;
COURS Java – Notions avancées

52 /** Position verticale du texte


53 */
private int y;

54 /** Panneau dans lequel apparait le texte


55 */
private JPanel panel;

private Thread textThread;

/** Creates new ThreadText */


public ThreadText(JPanel conteneur, String text) {
this.panel = conteneur;
this.text = text;
Dimension d = getRandomPosition();

x=d.width;
y=d.height;
textThread = new Thread(this);
textThread.start();
}

56 /** Exécute le thread pendant 15s avec une fréquence de clignotement de


150ms
57 */
58 public void run() {
59
60 try {
61 for (int i=0; i<100;i++)
62 {
63 draw();
64 textThread.sleep(150);
65 }
66 } catch ( InterruptedException ie) {}
67
68 }

69 /** Dessine le texte ou l'efface s'il est déjà affiché (Mode XOR)
70 */
public void draw() {
Graphics g = panel.getGraphics();
panel.setBackground(Color.white);
g.setXORMode(panel.getBackground());
g.drawString(text,x,y);
g.dispose();
}

71 /** Renvoie un objet Dimension correspondant à la taille du panneau


72 */
public Dimension getPanelSize() {

return panel.getSize();
}

73 /** Renvoie des coordonnées aléatoires dans la limite de la taille du


panneau
COURS Java – Notions avancées

74 */
public Dimension getRandomPosition() {

Dimension d = new Dimension(0,0);


Dimension panelSize = getPanelSize();
int xmax,ymax;
xmax = panelSize.width - 60;
ymax = panelSize.height - 20;
double nb = Math.random();
75 // Détermine des coordonnées au hasard
d.width = (int) Math.rint( xmax * ((1 - Math.random()) ));
d.height = (int) Math.rint( ymax * ((1 - Math.random()) ));
return d;
}
}
ThreadText.java

 Ligne 47-57 : Méthode run permettant de lancer le thread

/*
* JFrame.java
*
* Created on 2 octobre 2001, 16:56
*/
import java.awt.event.*;
import javax.swing.*;
import *;
/**
*
* @author genael
* @version
*/
public class ThreadFrame extends JFrame {

/** Creates new form JFrame */


public ThreadFrame(String text) {
threadCount =1;
setTitle(text);
initComponents ();
pack ();
}

private void initComponents() {


panel = new JPanel();
southPanel = new JPanel();
startButton = new JButton();
closeButton = new JButton();
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
exitForm(evt);
}
}
);

panel.setPreferredSize(new Dimension(300, 200));


COURS Java – Notions avancées

getContentPane().add(panel, BorderLayout.CENTER);
startButton.setText("D\u00e9marrer thread");
startButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
startButtonActionPerformed(evt);
}
}
);
southPanel.add(startButton);
closeButton.setText("Fermer");
closeButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt) {
closeButtonActionPerformed(evt);
}
}
);
southPanel.add(closeButton);
getContentPane().add(southPanel, BorderLayout.SOUTH);
}

private void closeButtonActionPerformed(ActionEvent evt) {


System.exit(0);
}

private void startButtonActionPerformed(ActionEvent evt) {

76 ThreadText thtxt = new ThreadText(panel,"Thread N." + threadCount++);


}

/** Exit the Application */


private void exitForm(WindowEvent evt) {
System.exit (0);
}

// Variables declaration
private JPanel panel;
private JPanel southPanel;
private JButton startButton;
private JButton closeButton;
private int threadCount;

}
Code source ThreadFramet.java

 Ligne 67 : Création d'un objet thread à chaque appui sur le bouton

E. Groupes de threads
Dans le cas où votre programme contient une grande quantité de threads, il peut être utile de
manipuler ces threads par groupe. Reprenons l'exemple du navigateur internet téléchargeant
des images. Lorsque vous cliquez sur Arrêter , le navigateur doit stopper le téléchargement des
COURS Java – Notions avancées

images. Si chaque image se télécharge par l'intermédiaire d'un thread et que tous , font partie
d'un groupe, nous disposons d'un moyen efficace de les stopper tous.

E.1. Construire un groupe de threads


Utilisez le constructeur suivant :
ThreadGroup g = new ThreadGroup("WebImages0047654");

La chaîne passée en argument du constructeur doit être unique

Pour ajouter des threads à ce groupe :


Thread th = new Thread (g, "Image1");

E.2. Interrompre les threads d'un groupe


Pour interrompre tous les threads d'un groupe, il suffit d'appeler la méthode interrupt du
groupe :
g.interrupt();

Un groupe peut posséder des groupes enfants. Le fait d'interrompre les threads du groupe
parent, interromps également les membres des groupes enfants

E.3. Connaître les threads actifs


Pour connaître le nombre de threads actifs d'un groupe, il faut appeler la méthode activecount
:
int nth = g.activeCount();

Il existe un nombre important de methods pour gérer ces groupes. Consultez la doc API Java 2
pour en savoir plus
COURS Java – Notions avancées

F. Synchronisation
F.1. Présentation du problème
Dans de nombreux cas, les threads partagent les mêmes objets et par conséquent, la
modification de ces objets par un thread pourrait avoir des conséquences fâcheuses pour les
autres thread notamment si ceux-ci modifient un objet en même temps.
Java propose un mécanisme de verrouillage des objets par un thread de telle sorte qu'aucun
autre thread ne puisse le modifier aussi. Néanmoins cela ne résoud pas tous les problèmes
puisque les threads peuvent également être interrompu pendant leur travail.
Voici une illustration de ce qui pourrait arriver sur un compte bancaire sans verrouillage des
données :
Thread 1 Thread 2
Tran sfert d e co m p te 1 ve rs V érifie la so m m e d es 2
co m p te 2 de 50 E u ro s co m p tes

D éb it
d e 5 0 E u ros du C om pte 1 C o m p te 2
co m p te 1 500 0

E xé cu tio n d u th read 1 450 0

T hread 2 in terrom pt Th read 1

C réd it
d e 5 0 E u ros du 450
co m p te 2

F in de l’e xécu tion


d u th re ad 1 450 50

D éroulem ent du tem ps


Fonctionnement non synchronisé

Pendant un certain laps de temps, la somme des 2 comptes sera inexacte !!!
Il faut donc que le Thread 1 soit certain de ne pas être interrompu pendant le transfert.

F.2. mot clé synchronised


Pour permettre au thread 1 de ne pas être interrompu, on utilise le mot clé synchronised
comme modificateur de la méthode qui ne doit pas être interrompue :
public synchronised void transfert( Compte source,
Compte dest, int montant) {
{
if (source.getSolde()<montant)
return;
source.solde = source.solde – montant;
dest.solde = dest.solde + montant;
}
Dans ce cas, la méthode ne sera pas interrompue entre la ligne 6 et 7.
COURS Java – Notions avancées

F.3. Verrous d'objets


Chaque fois qu'une méthode ou un bloc de code est affecté du mot clé synchronised , la
méthode est verrouillée et aucun autre objet ne peut appeler cette méthode. Le Thread pose
un verrou qu'il enlèvera en sortant de la méthode.
Ce système de verrouillage soulève tout de même un problème si jamais le thread verrouillé
effectue une action qui se prolonge dans le temps, voire infiniment. La conséquence est que
tous les autres threads n'ont plus aucune chance de s'exécuter (Sauf par découpage du temps
au niveau de l'OS dans le cas du multitâche préemptif).
Pour pallier à cet inconvénient, il y a la méthode wait.

F.4. wait et notify


wait
Lors de l'appel à la méthode wait , le thread enlève son verrou et vient se mettre en liste
d'attente pour l'exécution. L'objet étant déverrouillé, les autres threads peuvent alors
s'exécuter.
Il existe une différence importante entre un thread en sommeil et un thread ayant appelé
la méthode wait . En effet, ce dernier est dans une liste d'attente et le gestionnaire de
threads ne fera rien pour l'exécuter. Il risque donc d'être bloqué indéfiniment à moins
qu'un thread ne fasse appel à la méthode notify ou notifyAll.

notify et notifyAll
Donc , si un thread appelle sa méthode wait , il n'a aucun moyen de se débloquer lui-même. Il
doit donc compter sur les autres threads pour appeler la méthode notifyAll ou notify. Si ce n'est
pas le cas, nous sommes en présence d'un verrou mort (deadlock).
Pour éviter ce genre de situation, pensez toujours à appeler régulièrement la méthode notifyAll
ou notify.
La méthode notify donne l'ordre au gestionnaire des threads de débloquer un thread au hasard.
La méthode notifyAll débloque tous les threads qui deviennent par voie de conséquence
exécutables.
Threads exécutables
File d’attente des threads ayant
appelé la m éthode w ait
notifyA ll( )

le s
xéc u ta b
nn ent e
D e v ie

Thread bloqué
Thread exécuté
File d'attente des threads
COURS Java – Notions avancées

Il peut être dangereux d'appeler la méthode notify car vous ne savez pas quel thread sera
débloqué. Il est plus approprié d'employer la méthode notifyAll.

L'endroit le plus approprié pour appeler cette méthode est dans l'objet qui est susceptible de
changer la donne pour les threads mis dans la file d'attente avec wait.
Il faut savoir que le mécanisme de synchronisation ralentit les programmes qui l'utilise. C'est le
prix à payer pour un mécanisme assurant une très bonne intégrité des données.

G. Les threads et SWING


Dans une application graphique, la méthode main exécute un thread principal. Au moment de
l'appel à la méthode show ou setVisible de la fenêtre principale, un deuxième thread est crée. Il
est chargé de gérer la répartition des évènements. Pendant ce temps, le thread principal
s'exécute jusqu'à la fin du main.
Dans la plupart des cas, le thread principal prend fin rapidement et ceci dès l'affichage de la
fenêtre. Il reste donc le thread de répartition des évènements qui s'exécute et réagit aux
évènements comme l'appui sur un bouton ou l'appui sur une entrée de menu.
Le problème est que SWING n'est pas compatible avec les threads. En effet, la plupart des
méthodes des objets SWING ne sont pas synchronisées. La conséquence directe est que si un
des threads de l'utilisateur modifie des composants de l'interface utilisateur (Comme une
structure arborescente de type JTree , par exemple) , les données risquent d'être corrompues
si l'interface agit aussi sur ces composants.

G.1. Quand utiliser les threads ?


En général, dès qu'une action est susceptible de prendre du temps ou qu'elle n'est pas certaine
d'aboutir, il faut employer un thread pour ne pas monopoliser l'interface utilisateur. En effet, si
vous lancez une connexion réseau et que la connexion n'abouti pas, vous souhaiterez pouvoir
annuler pour faire autre chose.

Thread de répartition Thread de répartition


Thread utilisateur Thread utilisateur

Thread utilisateur bloqué pour


ne pas m onopoliser l’interface
utilisateur S W IN G

Exemple de fonctionnement des threads et SWING


COURS Java – Notions avancées

Chapitre 3 : Programmation réseau


A. Introduction
Voyons maintenant comment Java va nous permettre d'accéder au réseau par l'intermédiaire
de classes présentes dans l'API Java et qui répondent partiellement aux exigences d'Internet et
des réseaux informatiques.

A.1. Modèle OSI


Tout d'abord, dans un environnement construit autour du modèle OSI7, il existe plusieurs types
de connexion par paquets8 (TCP) ou par datagrammes9 (UDP). Ce modèle basée sur 7 couches
dépendantes les unes des autres représente une vue de l'esprit sur les différents niveaux sur
lesquels une machine et des utilisateurs peuvent échanger des informations sur le réseau :

A p plication

Présentatio n

Session

Tran spo rt

R éseau
Liais on de do nné es

Ph ysiqu e

Les 7 couches du modèle OSI

A.2. Protocoles
Les protocoles de communication réseau peuvent travailler sur des couches différentes et la
plupart d'entre eux sont dépendants des protocoles travaillant sur les niveaux inférieurs. Par
exemple , le protocole FTP10 qui travaille sur la couche Application est dépendant de TCP11 qui
lui, travaille sur la couche Transport.
Si vous connaissez la plupart des protocoles liés au modèle OSI, voici un schéma représentant
les protocoles ainsi que les couches sur lesquelles ils travaillent.

7
OSI : Open System Interconnection : Modèle basé sur une architecture à 7 couches
8
Paquets : Les données à transmettre sont scindées en plusieurs petites unités appelés Paquets
9
Datagrammes : Données envoyées sur le réseau sans aucune certitude sur leur réception sur l'hôte de destination
10
FTP : File Transfer Protocol : Protocole de transfert de fichiers très utilisé sur Internet
11
TCP : Transport Control Protocol : Protocole de transfert contrôlé
COURS Java – Notions avancées

Transm ission avec connexion Transm ission sans connexion


A p plication H TTP : H ypertText Transfer P rotocol TFTP : Trivial File Transfer P rotocol
FTP : File Transfer P rotocol S NM P : Sim ple N etw ork M anagem ent P rotocol
Présentatio n S M TP : S im ple M ail Transfer P rotocol ICM P : Inform ation Control M essage P rotocol
Telnet : Term inal R éseau IG M P, N NTP...
Session P O P 3 , IM AP 4, etc...

Tran spo rt TC P : Transfer Control Protocol U DP : U ser D atagram Protocol

R éseau IP : Internet P rotocol

Liais on de do nné es
P P P : P oint to P oint P rotocol

Ph ysiqu e

Correspondance modèle OSI et protocoles de la famille TCP/IP

A.3. Où travaille Java


A priori, les classes Socket , ServerSocket, DatagramPacket et DatagramSocket travaillent sur la
couche Transport du modèle OSI. Mais les classes INetAdress , URLConnection et URLEncoder
peuvent travailler sur les couches supérieures de ce même modèle.
Bien sûr, la plupart des développeurs JAVA ont à leur disposition des packages supplémentaires
leur permettant de travailler sur les couches supérieures sans avoir à se soucier de ce qui se
passe sur les couches inférieures. Par exemple, L'API Java-Mail conçue par SUN permet de
gérer l'envoi d'emails et prend en charge toutes les subtilités des protocoles SMTP ou POP3.
COURS Java – Notions avancées

B. Implémenter des sockets


B.1. Introduction
Les sockets sont des outils permettant d'effectuer une transmission en mode connecté entre
deux entités d'un réseau (Un client et un serveur par exemple). Les deux entités possèdent des
ports qu'ils peuvent utiliser pour envoyer et recevoir des données. Chaque entité possède
également une ou plusieurs adresses IP12 du style 192.168.5.12.
Donc , avec un port source , un port destination, une adresse IP source et une adresse IP
destination, une connexion est possible entre ces deux entités :

IN TER N ET
C LIEN T
P orts du serveur
P orts du client SE RVEU R
21
21 80
80 25
25 53
53 …

A dresse IP source : 213.12.14.10 A dresse IP destin ation : 212.198.113.9


Port source : 80 Port destination : 80

P aquet transm is par une socket


IP S ource IP D estination P ort S ource P ort destination D onnées
213.12.14.10 212.198.113.9 80 80 10101010101010101010...

Exemple de communication avec les sockets

B.2. Classe Socket


La classe Socket se situe dans la librairie java.net
Créer des sockets
La classe Socket associée aux flux de données, permet de lire et d'écrire des données sur le
réseau. La plupart du temps, les sockets sont utilisées pour se connecter à un serveur. En fait ,
les serveurs proposent des services (HTTP , FTP , TELNET…) que les clients peuvent utiliser.
La classe Socket permet à un client de se connecter à un hôte :
Socket s = new Socket(hote, port );
hote représente le nom de l'hôte et port représente le port sur lequel la socket va se connecter.
Par exemple, si vous vous connectez sur le port 80, vous aurez toutes les chances de créer une
connexion vers un serveur web qui pourra renvoyer des pages HTML13.
En créant une socket, vous pouvez également spécifier le port source de la connexion. Si le port
source n'est pas spécifié, le programme utilise un port libre choisi parmi tous ceux qui sont
libres. Voici la liste des constructeurs disponibles :

12
Adresse IP : Adresse sur 32 bits (Norme IPv4) utilisée pour communiquer sur un réseau Intranet ou Internet
13
HTML : HyperText Markup Language – Langage utilisé pour les pages internet
COURS Java – Notions avancées

Constructeurs de Socket
protected Socket()
Crée une socket en mode non connecté, avec une version par défaut de
SocketImpl. Utilisable par les classes enfant de Socket.
Socket(InetAddress address, int port)
Crée une connexion vers l'hôte ayant l'adresse et le port donnés en arguments
Socket(InetAddress address, int port, InetAddress localAddr,
int localPort)
Crée une connexion vers l'hôte ayant l'adresse et le port donnés en arguments.
localAddr et localPort paramètre les données sources de la socket
protected Socket(SocketImpl impl)
Crée une socket en mode non connectée avec une version spécifique de
SocketImpl
Socket(String host, int port)
Crée une connexion avec le nom de l'hôte spécifié ainsi que le port. L'appel à cette
méthode sous entend qu'il y a une résolution de nom en adresse IP.
Socket(String host, int port, InetAddress localAddr,
int localPort)
Même chose que la précédente avant en plus , des precisions sur l'adresse locale
et le port
Constructeurs de Socket

Il existe d'autres constructeurs non documenté ici car ils ne s'utiliseront plus dans les versions à
venir du JDK.

Lire et écrire des données


A partir de là, il est possible de créer un flux d'entrée ou un flux de sortie qui vous permettrons
de communiquer dans les deux sens avec le serveur. Chaque objet Socket dispose de deux
méthodes intéressantes pour le faire :
 getInputStream( ) : Retourne le flux permettant de lire les octets provenant du
serveur pour cette connexion
 getOutputStream() : Retourne le flux permettant d'écrire des octets à destination
du serveur pour cette connexion.
Socket s = new Socket(hote, port );
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();

Il est souvent plus utile, surtout sur Internet, de lire et d'écrire des caractères sur le réseau.
Pour le faire, il suffit d'utiliser la force de frappe des flux filtrés14 :
Socket s = new Socket(hote, port );
BufferedReader in = new BufferedReader (
new InputStreamReader(s.getInputStream()));

14
Flux filtrés : Voir chapitre sur les flux et les fichiers
COURS Java – Notions avancées

Dans notre exemple , nous obtenons un flux de caractères bufférisé provenant de l'hôte. Il
nous reste à effectuer une boucle de lecture des caractères :
String line;
while ( (line = in.readLine()) != null )
System.out.println(line);

Temps d'attente
Sur un réseau, il y a une ribambelle de raisons pour lesquelles la communication peut échouer.
Une socket qui tente de communiquer avec une autre machine non disponible peut bloquer un
programme indéfiniment. C'est pourquoi une socket peut attendre un certain temps défini par
le programmeur, puis abandonner la connexion si celle-ci ne peut se faire avant le délai imparti.
Ce délai se fixe grâce à la méthode setSoTimeout :
s.setSoTimeout(10000); // Timeout de 10s

Après ce délai, la socket est fermée. Toute opération de lecture ou d'écriture déclenche alors
une interruption de type InterruptedIOException. Par conséquent, il peut être vraiment utile de
lever cette exception au cas où :
try {
Socket s = new Socket(hote, port );
s.setSoTimeout(10000);
BufferedReader in = new BufferedReader (
new InputStreamReader(s.getInputStream()));
String line;
while ( (line = in.readLine()) != null )
System.out.println(line);
} catch (InterruptedIOException ie) {
System.out.println("Délai d'attente dépassé");
}

L'exemple précédent ne résout pas pour autant le problème puisque l'appel au constructeur
peut geler le programme si la connexion n'abouti pas. Il faut déjà posséder un objet de type
Socket avant d'appeler la méthode setSoTimeout.
Pour résoudre ce problème, il vous faudra créer la socket dans un thread15 séparé.

Socket et Thread
Pour illustrer le point qui vient d'être soulevé, voici une classe nommée SocketOpener
permettant d'ouvrir une socket dans un thread séparé et de renvoyer la socket lorsqu'elle est
ouverte et si elle n'a pas atteint la valeur de timeout:
import java.net.*;
import java.io.*;

class SocketOpener implements Runnable


{
77 // Méthode statique ouvrant la socket
public static Socket openSocket(String aHost, int aPort,int timeout)

15
Thread : Voir le chapitre concernant les threads
COURS Java – Notions avancées

{ SocketOpener opener = new SocketOpener(aHost, aPort);


Thread t = new Thread(opener);
t.start();
try
{ t.join(timeout);
}
catch (InterruptedException exception){}
return opener.getSocket();
}

public SocketOpener(String aHost, int aPort)


{ socket = null;
host = aHost;
port = aPort;
}
78 // Exécution dans un thread séparé
public void run()
{ try
{ socket = new Socket(host, port);
}
catch (IOException exception){}
}

public Socket getSocket()


{ return socket;
}

private String host;


private int port;
private Socket socket;
};
SocketOpener.java

Pour utiliser cette classe :


Socket s = SocketOpener.openSocket(host,port,10000);

if (s==null)
System.out.println("La socket n'a pas pu être ouverte");
else
// Travail avec la socket

B.3. Classe InetAddress


Cette classe est très utile pour utiliser les sockets avec des adresses internet. Elle permet la
résolution de nom en adresse IP sous Java et par voie de conséquence, elle fourni à la classe
Socket la possibilité de travailler directement sur des adresses internet.
Pour créer un objet InetAddress :
InetAddress adr = InetAddress.getByName("www.gita.greta.fr");
L'objet adr va contenir toutes les informations concernant cette adresse internet et notamment
les 4 octets de l'adresse IP récupérable dans un tableau de 4 bytes grâce à la méthode getBytes
:
byte [] tabl = adr.getBytes();
COURS Java – Notions avancées

Si vous exécutez le programme qui suit avec la commande suivante, vous obtiendrez, si vous
êtes connecté à Internet, l'adresse IP 212.37.208.183 :
java InetAddressTest www.gita.greta.fr

import java.net.*;
import java.io.*;

public class InetAddressTest {

public static void main ( String [] args ) {

try {

InetAddress adr = InetAddress.getByName(args[0]);


System.out.print("Adresse IP : " + adr.toString());
} catch (Exception e) {
System.out.println(e);
}
}
}
InetAddressTest.java

Une fonctionnalité intéressante de cette classe consiste à obtenir toutes les adresses IP
correspondant au nom DNS fourni. Il s'agit de la méthode statique getAllByName . Voici
l'exemple précédent modifié :
import java.net.*;
import java.io.*;

public class InetAllAddressTest {

public static void main ( String [] args ) {

try {

InetAddress[] adrs = InetAddress.getAllByName(args[0]);

for (int i=0; i<adrs.length;i++)


System.out.println("IP " + i +" : " + adrs[i].toString());
} catch (Exception e) {
System.out.println(e);
}
}
}

En exécutant la commande suivante :


java InetAllAddressTest www.yahoo.com
vous obtiendrez une liste d'adresses IP :
IP 0 : www.yahoo.com/64.58.76.222
IP 1 : www.yahoo.com/64.58.76.228
IP 2 : www.yahoo.com/64.58.76.177
IP 3 : www.yahoo.com/64.58.76.176
IP 4 : www.yahoo.com/64.58.76.229
COURS Java – Notions avancées

IP 5 : www.yahoo.com/64.58.76.225
IP 6 : www.yahoo.com/64.58.76.178
IP 7 : www.yahoo.com/64.58.76.227
IP 8 : www.yahoo.com/64.58.76.224
IP 9 : www.yahoo.com/64.58.76.226
IP 10 : www.yahoo.com/64.58.76.223
IP 11 : www.yahoo.com/64.58.76.179

B.4. Exemple de connexion à un serveur


Nous allons exécuter le programme suivant qui va réaliser une connexion vers un serveur
exécutant un programme qui renvoie systématiquement l'heure du serveur au client :
import java.net.*;
import java.io.*;

public class ClockClientSocket {

public static void main ( String [] args ) {

try {

Socket s = new Socket("localhost",8189);

BufferedReader in = new BufferedReader(


new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter( s.getOutputStream(),true);

String line;

out.println("quit");

while ( !(line=in.readLine()).toUpperCase().equals("STOP") )
System.out.println(line);

System.out.println("Fermeture de la connexion...");
s.close();

} catch (Exception e) {
System.out.println(e);
}
}
}
ClockClientSocket.java

 Ligne 10 : Ouvre une connexion avec l'hôte local sur le port 8189
 Ligne 12 : Crée le flux d'entrée de cette connexion comme un flux de caractères
bufferisé.
 Ligne 14 : Crée le flux de sortie de cette connexion comme un flux de caractères
 Ligne 18 : Envoie la commande quit permettant de mettre fin à la connexion
 Ligne 20 : Boucle lisant le flux entrant jusqu'à ce que le serveur renvoie la
commande STOP.
Voici ce que le programme affichera :
Bienvenue sur ClockServer - Version 1.0 - VALET G ©
***************************************************
Voici la date d'aujourd'hui :
COURS Java – Notions avancées

Wed Oct 17 17:02:51 CEST 2001


Echo :quit
Fermeture de la connexion...

Pour mettre en place, le serveur, il vous faut exécuter la commande suivante :


java ClockServer
puis exécuter le programme client sur la même machine :
java ClockClientSocket

C. Implémenter un serveur
C.1. Types de serveurs
Maintenant que nous avons vu la manière de se connecter à un serveur, nous allons passer aux
choses sérieuses en étudiant ce qui se passe côté serveur. En fait, un serveur est à l'écoute du
client qui se connecte et réagit en fonction des données qu'il reçoit.
Il existe 2 types de serveurs : le serveur capable de gérer un seul client et le serveur multi-
client.
Par exemple , un serveur HTTP16 est à l'écoute des requêtes de plusieurs clients et leur renvoie
les pages au format HTML demandées.
C lient 1

C lient 2
S erveur H TTP
Thread 1

Thread 2

Thread 3

Thread 4
C lient 3

C lient 4

Exemple de serveur http servant plusieurs clients

Dans le schéma ci-dessus, chaque connexion vers le client doit s'exécuter dans un threads
différents. Les clients peuvent donc effectuer des requêtes simultanément, le serveur saura
gérer l'envoi et la réception de données sur ces clients.

16
http : HyperText Transfer Protocol
COURS Java – Notions avancées

C.2. Classe ServerSocket


Exemple d'un serveur mono-client
Cette classe permet de gérer l'envoi et la réception de données vers un client. Une fois activée,
la socket serveur autorise le client à se connecter sur un port déterminé.
Pour créer une telle socket :
ServerSocket s = new ServerSocket (8189);
Ensuite, il faut créer une socket de type Socket permettant de gérer les flux vers et depuis le
client :
Socket client = s.accept();
l'objet client ne sera crée que si un client se présente sur le port 8189.
ATTENTION : La méthode accept() est bloquante. Ce qui signifie qu'elle ne se termine que
lorsqu'un client se connecte au port concerné. La conséquence directe est que le
programme ne se terminera jamais sans l'intervention d'un utilisateur sur le serveur. La
plupart du temps, il est indispensable de créer la socket serveur dans un thread séparé, de
manière à ne pas trop monopoliser le serveur qui a sûrement d'autres tâches à effectuer.
Nous verrons comment faire un peu plus loin dans ce chapitre.

Lorsque le client est connecté, le dialogue peut commencer entre le client et le serveur :
BufferedReader in = new BufferedReader (
new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream());
out et sa méthode print ou println permettra d'envoyer des caractères au client, alors que la
méthode readLine de in permettra une lecture bufferisée des requêtes du client.
Pour écrire au client :
out.println("Résultat de la requête");
out.flush();
Pour écouter le client :
String line = in.readLine();

Voici un programme d'exemple d'un serveur répondant au client connecté :


/*
* ClockSocket.java
*
* Created on 10 octobre 2001, 19:19
*/

import java.net.*;
import java.io.*;
import java.util.*;
/**
*
* @author Génael VALET
* @version 1.0 - Oct 2001
*/
public class ServerSocketTest {

public static void main(String[] args) {

try {
ServerSocket s = new ServerSocket(8189);
COURS Java – Notions avancées

while (true) {
Socket client = s.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader( client.getInputStream()));

PrintWriter out = new PrintWriter (


client.getOutputStream() ,true);

out.println( "Bienvenue sur le serveur" );

String line;
boolean fin=false;
while ( (line=in.readLine())!=null && !fin) {
out.println("Echo :" + line);
if (line.trim().toUpperCase().equals("QUIT")) {
fin = true;
out.println("STOP");
}
}
client.close();
}
} catch (SocketException se) {
System.out.println("Interruption de type SocketException");
} catch (Exception e) {
System.out.println(e);
}
}
}
ServerSocketTest.java

 Ligne 20 : Création de l'objet ServerSocket sur le port 8189


 Ligne 22 : Création d'une connexion de type Socket entre le client et le serveur.
Cette connexion sera utilisée par le serveur et le client pour lire et écrire.
 Lignes 23-27 : in et out sont les flux permettant l'écriture et la lecture sur le
client.
 Ligne 29 : Envoi d'un message de bienvenue sur le client
 Lignes 33 à 38 : Boucle de lecture de in jusqu'à ce que le client envoie la
commande QUIT. Si le client envoie QUIT, le serveur envoie le message d'arrêt
et quitte la boucle
 Ligne 40 : Fermeture de la connexion vers le client

Pour tester ce programme :


compilez-le et exécutez-le puis ouvrez une invite de commande. Ouvrez
une session telnet avec la commande

telnet localhost 8189


Le message de bienvenue s'affiche :
Bienvenue sur le serveur
Tapez n'importe quoi puis appuyez sur entrée :

Echo :Salut
Tapez QUIT puis Entrée :

Echo :QUIT
STOP
COURS Java – Notions avancées

Appuyez une dernière fois sur ENTREE :

Perte de la connexion à l'hôte.

C:\>
La session telnet se termine et les connexions sont perdues. Le serveur est libre et une autre
connexion client peut se produire.
Pour fermer le serveur, il suffit de fermer la fenêtre d'exécution

Exemple d'un serveur multi-clients


Le défaut du programme précédent est que seul un client peut se connecter en même temps.
Dans le monde du client/serveur , il est très courant qu'un serveur puisse accepter plusieurs
clients. Il faut donc que chaque client puisse être géré par le serveur dans un thread différent.
Voici le code source de la classe MultiServerSocket qui démarre une connexion vers le client
dans un thread différent pour chaque nouveau client :
import java.net.*;
import java.io.*;
import java.util.*;

/**
*
* @author Génael VALET
* @version 1.0 - Oct 2001
*/

public class MultiServerSocket {

public static void main(String[] args) {

try {
ServerSocket s = new ServerSocket(8189);
while(true) {
ThreadedSocket th = new ThreadedSocket(s.accept());
th.start();
}
} catch (SocketException se) {
System.out.println("Interruption de type SocketException");

} catch (Exception e) {
System.out.println(e);
}
}
}
MultiSocketServer.java

 Ligne 16 : Création de la socket serveur sur le port 8189


 Ligne 17 : Début de la boucle infinie
 Ligne 18 : Création d'un thread différent pour chaque nouveau client. La méthode
accept() attend la connexion d'un client.
COURS Java – Notions avancées

Le code source de la classe ThreadedSocket est le suivant :

import java.net.*;
import java.io.*;
import java.util.*;
79 /**
80 *
81 * @author Génael VALET
82 * @version 1.0 - Oct 2001
83 */
public class ThreadedSocket extends Thread {

private Socket client;

public ThreadedSocket(Socket client) {


this.client = client;
}

public void run() {

try {
BufferedReader buffer = new BufferedReader(
new InputStreamReader(client.getInputStream()));
PrintWriter writer = new PrintWriter(
client.getOutputStream(),true);
writer.println( "Bienvenue sur le serveur" );

String line;
boolean fin=false;
while ( (line=buffer.readLine())!=null && !fin) {
writer.println("Echo :" + line);
if (line.trim().toUpperCase().equals("QUIT")) {
fin = true;
writer.println("STOP");
}
}
client.close();
} catch (SocketException se) {
System.out.println("Interruption de type SocketException");
} catch (Exception e) {
System.out.println(e);
}
}
}
ThreadedSocket.java

 Ligne 17 : Méthode run du thread qui sera appelé par la méthode start()
 Lignes 20-23 : Création des flux entrant et sortant de la socket
 Ligne 24 : Envoi du message de bienvenue au client
 Ligne 28 : Boucle de lecture des informations en provenance du client
 Ligne 30 : Si le client renvoie la commande QUIT, la boucle se termine car la
variable fin sera égale à true.

Pour exécuter plusieurs clients, il vous suffit de démarrer plusieurs sessions telnet comme
décrit plus haut et de constater que le serveur répond à tous les clients .
COURS Java – Notions avancées

D. Connexion à des serveurs http


Sur Internet, un client désireux d'obtenir les pages web d'un site quelconque ne se soucie guère
de la plate-forme qui va lui renvoyer ces pages. Ce dont le client peut être sûr, c'est que
quelque soit le serveur atteint, il doit répondre aux requêtes de manière quasi identique. C'est
pourquoi les organismes qui contrôlent l'évolution d'internet se sont mis d'accord pour créer
un protocole de communication suivant les règles dictées par une RFC17

D.1. Classe URL


Composition d'une URL
La classe URL18 permet de manipuler des adresses Internet sur différents protocoles et de
récupérer des informations sur des parties de l'adresse. En effet une adresse Internet est
constituée :
 Du protocole ( HTTP, FTP …)
 Du nom DNS du domaine ( comme www.gita.greta.fr )
 Du chemin de la ressource ( comme /formations )
 Du nom de la ressource ( comme fiche.asp )
 Des informations sur la requête ( comme id=76)
 Du nom du signet au sein de la page ( comme dates)
Une telle adresse ressemblerait à ceci :
http://www.gita.greta.fr/formations/fiche.asp?id=76#dates

Méthode openConnection
La classe URL permet aussi, grâce à sa méthode openConnection d'effectuer une connexion vers
l'adresse qu'elle représente.
URL url = new URL ("http://www.gita.greta.fr/index.htm");
URLConnection con = url.openConnection();

Les constructeurs de la classe URL génèrent une exception de type


MalformedURLException si le protocole spécifié n'existe pas ou si aucun protocole n'est
spécifié. Il faut donc lever cette exception systématiquement.

Méthode openStream
Cette méthode permet d'ouvrir une connexion et de récupérer un flux d'entrée de données
depuis le serveur correspondant à cette connexion :
InputStream in = url.openStream();
Cette méthode est équivalente à :
InputStream in = url.openConnection().getInputStream();

17
RFC – Request For Comment – Groupe de travail régissant les normes des différents protocoles informatiques
18
URL – Uniform Ressource Locator – Adresse Internet
COURS Java – Notions avancées

D.2. Classe URLConnection


Instanciation
Cette classe abstraite sera très utile pour en connaître un peu plus sur le serveur qui fourni les
données. En effet, il peut être utile de connaître la version de http supportée par le serveur de
manière à lui présenter des requêtes bien formulées.
Cette classe peut se connecter à des serveurs sur plusieurs types de protocoles (http, FTP,
gopher…). Pour effectuer une connexion vers un serveur http, il vaut mieux utiliser la classe
HttpURLConnection .
Pour effectuer une connexion vers un serveur, il faut respecter l'ordre des opérations. Tout
d'abord, il vous faut créer une connexion avec, si besoin est, la classe URL vue précédemment.
URL url = new URL ("http://www.gita.greta.fr/index.htm");
URLConnection con = url.openConnection();

setDoInput et setDoOutput
Ces méthodes sont utilisées pour déterminer si vous allez uniquement recevoir des données ou
si vous allez en envoyer. Elles vont fixer les champs booléens doInput et doOutput.
Par défaut, toute nouvelle connexion fixe le champ doInput à la valeur true et celle de doOutput
à false.

Méthode setIfModifiedSince
L'appel à cette méthode va déterminer si il est nécessaire de recharger l'objet souhaité selon
des critères de temps. En effet, le paramètre à transmettre avec la méthode représente le
nombre de millisecondes écoulées depuis le 1er Janvier 1970. Si l'objet n'a pas été modifié
depuis la date représentée par ce paramètre, alors l'objet ne sera pas rechargé.
Méthode setUseCaches
Détermine l'utilisation du cache en fixant le champ booléen useCaches à true pour activer le
cache ou à false pour recharger l'objet quoiqu'il arrive. Cette méthode n'est utile que pour les
applets
Méthode connect
Cette méthode ouvre une socket vers le serveur et demande à celui-ci les informations d'en-
tête de l'objet demandé. Ces informations représentent les propriétés de l'objet comme , la
date de dernière modification, le type de contenu (content type), la taille de l'objet (content
length), le type de codage (content encoding), ou encore la date d'expiration (expiration)

Les méthodes suivantes serviront à obtenir ces informations :

Méthodes d'accès aux informations d'en-tête


String getContentEncoding()
int getContentLength()
COURS Java – Notions avancées

String getContentType()
long getDate()
long getExpiration()
long getLastModified()

Méthode getHeaderFieldKey
Voilà comment obtenir les informations d'en-tête du serveur. Voici la signature de cette
méthode :
String getHeaderFieldKey( int n )
n représente le nième champ d'en-tête. Il n'est pas possible de savoir combien de champs le
serveur contient. Cette méthode renvoie null lorsqu'il n'y pas plus de champs.
Voici un programme permettant d'obtenir ces informations auprès d'un serveur :

import java.net.*;
import java.io.*;

public class URLConnectionTest {

public static void main (String [] args) {

try {
URL url = new URL("http://www.gita.greta.fr");
URLConnection con = url.openConnection();
int n = 1;
String key;
con.connect();
while ((key = con.getHeaderFieldKey(n))!= null) {
String valeur = con.getHeaderField(n++);
System.out.println(key + ":" + valeur);
}
} catch (MalformedURLException mie) {
System.out.println("Url incorrecte");
} catch ( IOException ie) {
System.out.println("Problème d'entrées sorties");
System.out.println(ie);
}
}
}
URLConnectionTest.java

Voici la réponse obtenue du serveur :


Server:Microsoft-IIS/4.0
Content-Location:http://www.gita.greta.fr/index.htm
Date:Thu, 18 Oct 2001 11:10:56 GMT
Content-Type:text/html
Accept-Ranges:bytes
Last-Modified:Tue, 03 Jul 2001 10:01:04 GMT
ETag:"3a837c12a73c11:396c55"
Content-Length:21978
COURS Java – Notions avancées

D.3. Lire les données provenant de serveurs


Il ne nous reste plus qu'a lire les données envoyées par les serveurs en récupérant un flux
d'entrée par la méthode getInputStream de la classe URLConnection :
import java.net.*;
import java.io.*;
84
public class URLConnectionReadTest {

public static void main (String [] args) {

try {
URL url = new URL("http://homewk");
URLConnection con = url.openConnection();
85 BufferedReader in = new BufferedReader(
86 new InputStreamReader(con.getInputStream()));

String line;
while ( (line=in.readLine())!=null)
System.out.println(line);

} catch (MalformedURLException mie) {


System.out.println("Url incorrecte");
} catch ( IOException ie) {
System.out.println("Problème d'entrées sorties");
System.out.println(ie);
}
}
}
URLConnectionReadTest.java

D.4. Ecrire des données vers un serveur


Lorsque vous saisissez des données dans un formulaire, les données sont envoyées selon deux
méthodes différentes. La méthode GET encapsule les données dans l'URL alors que la méthode
POST envoie les données dans une requête http.
Méthode GET
Aujourd'hui, la méthode GET est de moins en moins utilisée, sauf lorsque la taille des données
envoyées et leur confidentialité ne sont pas un problème.
Lorsque vous utilisez le moteur de recherche Altavista pour trouver des ressources pour Java et
que vous appuyez sur Recherche, le navigateur envoie des informations au serveur. Voici l'URL
composée à ce moment :
http://fr.altavista.com/q?pg=q&q=java&kl=fr&what=fr&mm=1&search.x=26
&search.y=1
La 1ère partie de l'URL concerne le nom de domaine et donc celui du serveur qui héberge les
pages. La 2ème partie , en gras ci-dessus correspond aux données envoyées par la méthode GET.
Chaque champ du formulaire est séparé par des &. Par exemple , le champ kl vaut fr , ce qui
signifie que tous les résultats de la recherche devront être de langue française.
COURS Java – Notions avancées

Méthode POST
La méthode POST réalise la même chose mais l'URL renvoyée est plus simple puisque les
données sont cachées au sein des requêtes http.
Ecrire des données
En Java, nous allons envoyer des données au serveur du GITA par la méthode POST. Le but
étant de connaître le nombre de visiteurs à l'instant sur le site, nous allons effectuer une
requête auprès du serveur suivant :
http://www.gita.greta.fr/getinfo.asp
avec les informations transmises par POST
visit=true
Ce qui signifie que les données de retour devront contenir le nombre de visiteurs présents sur
le site.
Il faut commencer par créer correctement un objet URLConnection puis le paramétrer pour
qu'il accepte un flux sortant. Cela passe donc par la création d'un flux de type PrintWriter
obtenu grâce à la méthode getOutputStream() de la classe URLConnection:

URL url = new URL("http://www.gita.greta.fr/getinfo.asp");


URLConnection con = url.openConnection();

con.setDoOutput(true); // Autorise le flux sortant

PrintWriter out = new PrintWriter(con.getOutputStream());

La deuxième étape consiste à écrire les informations devant être transmises par la méthode
POST
out.print("visit=true");
out.close();

Il ne reste plus qu'à lire les données renvoyées par le serveur par le biais d'un flux de caractères
bufferisé et d'une boucle s'arrêtant lorsqu'il n'y a plus de données :

BufferedReader in = new BufferedReader( new InputStreamReader(


con.getInputStream()));

String line;
while ( (line=in.readLine())!=null)
System.out.println(line);
Nous obtenons alors le résultat suivant à l'écran :
Le nombre de visiteurs présents sur le site est de 12

Voici le code complet du programme :


import java.net.*;
import java.io.*;

public class URLConnectionWriteTest {

public static void main (String [] args) {

try {
URL url = new URL("http://www.gita.greta.fr/getinfo.asp");
COURS Java – Notions avancées

URLConnection con = url.openConnection();


con.setDoOutput(true);
PrintWriter out = new PrintWriter(con.getOutputStream());
out.print("visit=true");
out.close();

BufferedReader in = new BufferedReader(


new InputStreamReader(con.getInputStream()));

String line;
while ( (line=in.readLine())!=null)
System.out.println(line);

} catch (MalformedURLException mie) {


System.out.println("Url incorrecte");
} catch ( IOException ie) {
System.out.println("Problème d'entrées sorties");
System.out.println(ie);
}
}
}
URLConnectionWriteTest.java

D.5. Classe URLEncoder


Les caractères ASCII doivent codés différemment dans une URL. En effet, de manière à éviter
les caractères qui ne sont pas compris par tous les serveurs. Voici les règles appliquées aux
caractères :
 Tous les caractères allant de 'a' à 'z', de 'A' à 'Z', de '0' à '9', et ".", "-", "*", "_"
sont inchangés.
 Le caractère d'espacement ' ' est converti en un signe '+'.
 Tous les autres caractères sont converti en 3 caractères %xy ou xy représente la
valeur héxadécimale ASCII du caractère.
L'adresse suivante :
http://www.gita.greta.fr/fiche.asp?id=12
devient
http%3A%2F%2Fwww.gita.greta.fr%2Ffiche.asp%3Fid%3D1

Ce résultat est obtenu en appelant la méthode statique encode(String s) de la classe


URLEncoder :
String normal = "http://www.gita.greta.fr/fiche.asp?id=12";
String coded = URLEncoder.encode(normal);

D.6. Classe URLDecoder


Elle fonctionne de la même façon que URLEncoder mais effectue le décodage. La méthode à
appeler est decode.
COURS Java – Notions avancées

Chapitre 4 : Bases de données avec JDBC


A. Introduction
Incontournable dans le monde de l'informatique, les bases de données sont le moteur de toute
application ayant à traiter et sauvegarder beaucoup d'informations. Java se devait
d'implémenter une interface digne de ce nom et c'est chose faite depuis l'été 1996 avec le kit
JBDC19. Depuis, le travail acharné de Sun a permis l'intégration complète des bases de données
dans les kits fournis par l'éditeur. D'abord avec l'arrivée de JDBC 1 puis JDBC 2.
Architecturé autour du langage SQL20 , JDBC possède des atouts qui font de Java, le langage
idéal pour la connectivité aux bases de données. Voici les principaux avantages de JDBC :
 Les programmes développés en Java avec JDBC sont entièrement portables et
peuvent fonctionner sur n'importe quel ordinateur disposant de l'environnement
Java
 Quelle que soit le type de base de données, les programmes écrits avec JBDC
fonctionneront, quasiment sans modification du code. Un programme écrit pour
accéder aux données sur un serveur SQL Server de Microsoft fonctionnera
également sur base Oracle
 JDBC propose plusieurs niveaux de drivers JDBC (voir plus loin dans ce cours)
permettant d'offrir une compatibilité maximum avec des applications existantes
tout en acceptant la présence de code non Java (C++ par exemple). C'est le cas de
l'interface ODBC21

19
Java DataBase Connectivity
20
Structured Query Language
21
Open DataBase Connectivity
COURS Java – Notions avancées

B. Présentation
B.1. Schéma

Schéma d'ensemble de l'environnement JDBC

B.2. Le gestionnaire de pilotes (JDBC Driver Manager)


Il s'agit de l'organe principal de JDBC. Il coordonne les différents pilotes, ce qui permet à un
même programme d'accéder à plusieurs bases de marque différente. La classe DriverManager
fourni dans le package java.sql s'exécute dans un environnement statique, ce qui lui permet de
gérer efficacement les connexions aux bases de données. C'est également lors de l'utilisation de
cette classe, que les différentes pilotes sont enregistrés au près du gestionnaire.

B.3. Les pilotes


Il existe plusieurs types de pilote JDBC :
 Pilote de type I
 Pilote de type II
 Pilote de type III
 Pilote de type IV

Ceci permet, comme nous allons le voir, de s'adapter à tout type d'infrastructure existante.
COURS Java – Notions avancées

Pilote de type I
 Ce type de pilote utilise l'interface ODBC qui , dans le monde Windows permet
de se connecter à tout type de base de données.
 Les appels de JDBC sont convertis en appels ODBC , ce qui en terme de
performance, n'est pas toujours l'idéal
 Java utilise une librairie native écrite en C ce qui exclue de le faire fonctionner au
sein d'une applet
 Il est fourni avec le kit Java par l'intermédiaire de la classe
sun.jdbc.odbc.JdbcOdbcDriver
Voici le code nécessaire pour enregistrer ce type de pilote auprès du gestionnaire :
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

Pilote de type II
 Une partie de ce pilote est écrit en Java et l'autre partie dans le langage
propriétaire natif de la base de données.
 Les appels JDBC sont alors convertis en appels vers les API natives de la base de
données
 Cela implique que pour accéder à ce type de pilote, il faut installer sur la machine
les API natives
 Les appels au code natif exclue d'utiliser ce type de pilote au sein d'une applet
 Ces pilotes sont généralement payants et écrits par des sociétés tierces ou par
l'éditeur de la base de données
 La portabilité du code n'est plus assurée à cause de la partie langage natif

Pilote de type III


 Pilote 100% Java utilisant une API réseau avec un programme appelé
middleware22 , chargé de communiquer avec la base de données.
 Ce pilote est donc totalement indépendant de la base de données, ce qui constitue
une bonne solution performante et portable
 Comme aucun appel à un langage natif n'est effectué, le pilote de type III est
utilisable avec les applets (à condition que l'applet soit stockée sur le même
serveur que la base de données)

Pilote de type IV
 Pilote 100% Java qui se connecte directement à la base de données sans la
nécessité d'un programme middleware
 Les requêtes sont alors directement traduites et envoyés grâce à l'utilisation des
sockets23
 Le pilote de type IV est utilisable avec les applets (à condition que l'applet soit
stockée sur le même serveur que la base de données).

Pour trouver un pilote correspondant à votre base de données, utilisez l'adresse :

22
Programme intermédiaire agissant comme un traducteur entre une application cliente et une application
serveur. C'est un des éléments de l'architecture 3 tiers.
23
Elément de programmation permettant d'effectuer une connexion à un hôte distant via le réseau
COURS Java – Notions avancées

http://java.sun.com/products/jdbc
Sachez que la plupart des éditeurs de bases de données fournissent des pilotes de type III ou IV
, ce qui constitue un gage de performance et de compatibilité avec le langage SQL.

C. Mise en œuvre de JDBC


C.1. Introduction
La mise en œuvre de JDBC suppose que vous ayez déjà des connaissances minimales sur le
langage SQL et la structure d'une base de données. Par exemple, si le code SQL suivant vous
laisse de marbre, il faut vous procurer immédiatement un ouvrage traitant la question :
SELECT * FROM Clients WHERE nom='DUPONT' ORDER BY nom

C.2. Se procurer un pilote


En effet, la 1ère tâche à effectuer est de se procurer le pilote Java de la base de données avec
laquelle vous souhaitez travailler. Pour cela, vous pouvez vous aider de l'URL suivante :
http://java.sun.com/products/jdbc

Pour travailler avec la passerelle JDBC/ODBC , pas besoin de pilote, il est intégré dans le kit Java
de Sun.

La plupart du temps, le pilote se présente sous la forme d'un fichier JAR24. Ce fichier doit être
positionné dans un répertoire liste dans la variable CLASSPATH25. Le nom du package fourni
correspond toujours à un nom faisant partie d'un espace de noms, comme on peut les trouver
sur Internet :
com.mysql.jdbc
Ci-dessus, un exemple de nom de package pour le driver de la base de données MySql que vous
pouvez vous procurer gratuitement à l'adresse :
http://www.mysql.com/products/connector-j

C.3. Importer le package nécessaire


Votre programme doit comporter l' import nécessaire à l'utilisation de JDBC :
import java.sql.*;

Inutile d'importer le package contenant le pilote. Les bonnes classes seront utilisées lors de
l'enregistrement du pilote par le gestionnaire de pilotes.

24
Java ARchive
25
Classpath : Variable d'environnement contenant la liste des répertoires concernés par Java susceptible de
contenir des packages ou des archives utiles pour la compilation
COURS Java – Notions avancées

C.4. Enregistrer le pilote


L'appel à la méthode statique forName de la classe Class permet l'enregistrement. Voici un
exemple permettant d'enregistrer un pilote MySql :
Class.forName("com.mysql.jdbc.Driver");

Voici le même exemple pour travailler avec une base de données Access via l'interface OBDC :
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

L'exemple ci-dessus permet de travailler avec n'importe qu'elle base de données (Et pas Access
seulement) à partir du moment où l'on possède le pilote ODBC approprié. L'utilisation du pont
JDBC/ODBC ne fait que reporter le problème du pilote vers ODBC.

C.5. Etablir la connexion à la base de données


URL de connexion
La base de données peut-être atteinte grâce à une URL26 de connexion. Cette URL est
composée de plusieurs parties :
jdbc:mysql://bd.diderot.org:3306/diderot

Préfixe indiquant URI de connexion Nom de la base sur le


l'utilisation de indiquant l'adresse serveur distant. Cela
JDBC et du pilote du serveur où se permet de travailler avec
pour MySql situe la base de plusieurs bases sur un
données même serveur
Chiffre indiquant le
port à contacter
sur le serveur
distant où est
enregistré la base

Voici un exemple d'URL de connexion utilisant le pont ODBC/JDBC :


jdbc:odbc:nom_de_la_source_de_donnees

Le pont JDBC/OBDC suppose que la base et ODBC sont installés sur la même machine locale. C'est
pourquoi, dans l'URL proposée ci-dessus, ne figure pas le nom d'un serveur distant mais le nom
de la source de données locale.

26
Uniform Ressource Locator
COURS Java – Notions avancées

Méthode getConnection
Rappelons-nous que le gestionnaire de pilote (Driver Manager) est chargé de nous fournir les
connexions par l'intermédiaire d'un objet, instance de la classe Connection.

Voici un exemple d'ouverture d'une connexion vers une base de données


String url = "jdbc:mysql://bd.diderot.org:3306/diderot";

Connection c;
c = DriverManager.getConnection(url,"username","password");

appel à la nom mot de passe


méthode statique d'utilisateur transmis à la
getConnection de transmis à la BD
la classe BD
Il existe plusieurs méthodes getConnection dont voici les signatures :
DriverManager
Méthodes getConnection de DriverManager
static Connection getConnection(String url)
Essaie d'effectuer une connection vers la base spécifiée par l'URL
static Connection getConnection(String url, Properties info)
Essaie d'effectuer une connection vers la base spécifiée par l'URL.
info est une instance de la classe Properties qui contient les différents
paramètres sous forme de couple nom/valeur correspondant aux
paramètres d'ouverture de connexion ( user, password, ….)
static Connection getConnection(String url, String user,
String password)
Essaie d'effectuer une connection vers la base spécifiée par l'UR
avec le nom d'utilisateur et le mot de passe fournis en paramètres

Lors de l'appel à getConnection , le gestionnaire de pilotes essaie tous les pilotes qui ont été
enregistrés par l'appel à Class.forName(…) jusqu'à ce qu'il obtienne une connexion vers la base
désignée par l'URL. Cela signifie que si plusieurs pilotes enregistrés permettent de se connecter à
la base, c'est le 1er pilote enregistré qui aura gain de cause.

C.6. Créer une zone de description de requête (Statement)


La zone de description de requête est implémenté grâce à l’interface Statement du package
java.sql. Il s'agit de créer un espace permettant d'exécuter une ou plusieurs requêtes SQL.
Il existe 3 types de Statement :
 Statement : Permet d'effectuer des requêtes simples comme la lecture, la
modification ou l'ajout de quelques enregistrements.
 PreparedStatement : Permet d'effectuer des requêtes pré compilées , gages de
performances plus élevées, surtout lorsque ces requêtes se répètent plusieurs fois.
Ces requêtes peuvent également faire passer des paramètres d’exécution
COURS Java – Notions avancées

 CallableStatement : Permet de faire appel à des procédures stockées27

Pour obtenir un objet Statement , il faut appeler la méthode createStatement de la classe


Connection :
String url = "jdbc:mysql://bd.diderot.org:3306/diderot";

Connection c;
c = DriverManager.getConnection(url,"username","password");

Statement st = c.createStatement();

A ce stade, le Statement est initialisé mais aucune requête vers la BD n'est effectuée.

C.7. Exécuter une requête


Voilà le moment tant attendu où nous allons pouvoir obtenir des données. Pour cela, il faut
utiliser la classe ResultSet , chargée d'organiser les données venant de la base selon des lignes
et des colonnes. Une colonne (Column) correspond à toutes les valeurs d'un champ de la table.
Une rangée (Row) correspond à la valeur de chaque champ de la table:
Colonn
e Rangée ou
ligne
nom prénom noEmploye Tel Email
DUPONT Jean 1456321 0145342325 [email protected]
DURANT Jacques 1213101 0223425434 [email protected]
BRASSENS Georges 1214564 0134231234 [email protected]

On obtient l'objet ResultSet en appelant la méthode executeQuery de l'objet Statement :


String url = "jdbc:mysql://bd.diderot.org:3306/diderot";

Connection c;
c = DriverManager.getConnection(url,"username","password");

Statement st = c.createStatement();

String strSql = "SELECT * FROM clients WHERE ville='paris' ";


ResultSet rs = st.executeQuery(strSql);

Lance l'exécution de la requête et Prépare une chaîne de caractère


renvoie l'objet ResultSet qui contenant la requête qui permet
permettra de lire et d'écrire des d'obtenir tous les clients résidant à
données dans la base Paris

27
Procédures complexes programmées par l'administrateur de la base de données pour faciliter la manipulation
de données par l'utilisateur. Ces procédures sont comme des fonctions appelées avec , si nécessaire, des
paramètres d'exécution définis par l'utilisateur.
COURS Java – Notions avancées

C.8. Lire des données dans un ResultSet


Pour exploiter les données contenues dans un ResultSet , il n'est pas nécessaire de connaître
leur nature. Néanmoins, cela facilité la manipulation des données. En fait, chaque type SQL, est
associé avec un type primitif Java, ce qui devrait nous permettre de stocker les données dans
des variables Java.
Voici un tableau de correspondance entre les types SQL et les méthodes Java de ResultSet
permettant de lire ces données :

TYPE SQL Méthodes de ResultSet pouvant être utilisée


TINYINT: getByte (usage recommandé)
Peut-être lu aussi par getShort, getInt, getLong, getFloat,
getDouble, getBigDecimal, getBoolean, getString, getObject
SMALLINT: getShort (usage recommandé)
Peut-être lu aussi par getByte, getInt, getLong, getFloat,
getDouble, getBigDecimal, getBoolean, getString, getObject
INTEGER: getInt (usage recommandé)
Peut-être lu aussi par getByte, getShort, getLong, getFloat,
getDouble, getBigDecimal, getBoolean, getString, getObject
BIGINT: getLong (usage recommandé)
Peut-être lu aussi par getByte, getShort, getInt, getFloat,
getDouble, getBigDecimal, getBoolean, getString, getObject d
REAL: getFloat (usage recommandé)
Peut-être lu aussi par getByte, getShort, getInt, getLong,
getDouble, getBigDecimal, getBoolean, getString, getObject
FLOAT: getDouble (usage recommandé)
Peut-être lu aussi par getByte, getShort, getInt, getLong, getFloat,
getBigDecimal, getBoolean, getString, getObject
DOUBLE: getDouble (usage recommandé)
Peut-être lu aussi par getByte, getShort, getInt, getLong, getFloat,
getBigDecimal, getBoolean, getString, getObject
DECIMAL: getBigDecimal (usage recommandé)
Peut-être lu aussi par getByte, getShort, getInt, getLong, getFloat,
getDouble, getBoolean, getString, getObject

NUMERIC: getBigDecimal (usage recommandé)


Peut-être lu aussi par getByte, getShort, getInt, getLong, getFloat,
getDouble, getBoolean, getString, getObject
BIT: getBoolean (usage recommandé)
Peut-être lu aussi par getByte, getShort, getInt, getLong, getFloat,
getDouble, getBigDecimal, getString, getObject
CHAR: getString (usage recommandé)
Peut-être lu aussi par getByte, getShort, getInt, getLong, getFloat,
getDouble, getBigDecimal, getBoolean, getDate, getTime,
getTimestamp, getAsciiStream, getUnicodeStream, getObject
VARCHAR: getString (usage recommandé)
Peut-être lu aussi par getByte, getShort, getInt, getLong, getFloat,
getDouble, getBigDecimal, getBoolean, getDate, getTime,
getTimestamp, getAsciiStream, getUnicodeStream, getObject
COURS Java – Notions avancées

LONGVARCHAR: getAsciiStream, getUnicodeStream (usage recommandé pour


toutes)
Peut-être lu aussi par getByte, getShort, getInt, getLong, getFloat,
getDouble, getBigDecimal, getBoolean, getString, getDate,
getTime, getTimestamp, getObject
BINARY: getBytes (usage recommandé)
Peut-être lu aussi par getString, getAsciiStream,
getUnicodeStream, getBinaryStream, getObject
VARBINARY: getBytes (usage recommandé)
Peut-être lu aussi par getString, getAsciiStream,
getUnicodeStream, getBinaryStream, getObject
LONGVARBINARY: getBinaryStream (usage recommandé)
Peut-être lu aussi par getString, getBytes, getAsciiStream,
getUnicodeStream, getObject
DATE: getDate (usage recommandé)
Peut-être lu aussi par getString, getTimestamp, getObject
TIME: getTime (usage recommandé)
Peut-être lu aussi par getString, getTimestamp, getObject
TIMESTAMP: getTimestamp (usage recommandé)
Peut-être lu aussi par getString, getDate, getTime, getObject
Tableau de correspondance SQL > Type Java

Le code suivant permet de lire un nom et le prénom dans une base de données de clients :
String url = "jdbc:mysql://bd.diderot.org:3306/diderot";

Connection c;
c = DriverManager.getConnection(url,"username","password");

Statement st = c.createStatement();

String strSql = "SELECT * FROM clients WHERE ville='paris' ";


ResultSet rs = st.executeQuery(strSql);
rs.next();
String nom = rs.getString("nom"); L'appel à getString suppose
String prenom = rs.getString(2);
que l'on connaît le nom du
champ.
Ici, l'appel à getString suppose que
l'on connaît le numéro de colonne
du champ (Ici prenom est la 2ème
colonne dans la table
COURS Java – Notions avancées

D. Le traitement des exceptions


Evidemment, lorsque vous vous connectez à une base de données, vous n'êtes jamais sûr que :
 La base est accessible
 Vous êtes bien autorisé à accéder à la base
 La requête SQL que vous avez formulée est correcte
 Le pilote est bien enregistré et opérationnel
 …

Donc, pour éviter de bloquer votre programme Java dans le cas où une erreur se produit, vous
aurez recours à l'utilisation des exceptions, d'autant plus que cela vous est imposé de la part du
compilateur. En effet, toutes les opérations relatives aux bases de données sont susceptibles de
renvoyer une exception de type SQLException.
Vos programmes devront donc être conçus pour prévoir les actions à mener au cas où les
opérations vers les bases de données se déroulent mal.
Voici un exemple complet de programme permettant de se connecter à une base de données
avec la gestion des exceptions :
try { Se produit si le
Class.forName("com.mysql.jdbc.Driver"); pilote désigné n'est
pas présent dans le
} catch (ClassNotFoundException ex) {
System.out.println("Pilote JDBC non enregistré");système Java
}

String url = "jdbc:mysql://bd.diderot.org:3306/diderot";

try {
Connection c;
c = DriverManager.getConnection(url,"username","password");

Statement st = c.createStatement();

String strSql = "SELECT * FROM clients WHERE ville='paris' ";


ResultSet rs = st.executeQuery(strSql);

rs.next() ;

String nom = rs.getString("nom");


String prenom = rs.getString(2);

} catch (SQLException ex) {


System.out.println("Erreur SQL :"+ex.getMessage());
}

Se produit si l'une des


instructions précédentes
s'est mal terminée.
COURS Java – Notions avancées

E. Caractéristiques d'un ResultSet


Il existe plusieurs types de ResultSet. Cette variété de types permet de proposer aux
programmeurs des choix en termes de performance et de "fraîcheur" des données. En effet,
maintenir un ResultSet à jour en rendant visible les modifications effectuées par d'autres
utilisateurs est assez coûteux en ressources systèmes. Par contre, un ResultSet moins
performant permet de moins charger le moteur de la base de données.
Le choix d'un type de ResultSet se détermine au moment de la création de l'objet Statement. Vous
devez fournir à la méthode createStatement de la classe Connection les arguments nécessaire à
ce choix.

E.1. ResultSet de type FORWARD_ONLY


C'est le type par défaut si vous ne spécifiez pas le contraire. Ce type permet de parcourir un
ResultSet en avant seulement. Ce qui signifie, qu'il ne vous sera pas possible de retourner en
arrière pour relire un enregistrement :

Voici un exemple :
Connection c;
c = DriverManager.getConnection(url,"username","password");

Statement st = c.createStatement(ResultSet.FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);

L'argument est un champ Spécifie que le ResultSet ne


statique de la classe ResultSet peut pas être mis à jour

E.2. ResultSet de type TYPE_SCROLL_INSENSITIVE


Pour ce type, il vous sera possible de parcourir le ResultSet dans n'importe quel sens, par contre
les modifications effectuées par d'autres utilisateurs de la base de données ne seront pas
répercutées.
Voici l'exemple d'un ResultSet non modifiable, de type insensible aux modifications faîtes par
ailleurs mais que l'on peut parcourir dans tous les sens :
Connection c;
c = DriverManager.getConnection(url,"username","password");

Statement st = c.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);

E.3. ResultSet de type TYPE_SCROLL_SENSITIVE


Ce type permet de voir les modifications effectués par d'autres utilisateurs. Naturellement, ce
type de ResultSet oblige JDBC à obtenir des informations à jour en permanence. La
conséquence est qu'un trop grand nombre de connexion associé à des ResultSet de type
TYPE_SCROLL_SENSITIVE peut engendrer une surcharge du moteur de la base de données.
COURS Java – Notions avancées

Voici l'exemple d'un ResultSet non modifiable, de type sensible aux modifications faîtes par
ailleurs et que l'on peut parcourir dans tous les sens :
Connection c;
c = DriverManager.getConnection(url,"username","password");

Statement st = c.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);

E.4. Modifier des enregistrements


Pour pouvoir modifier des enregistrements, il faut le préciser lors de l'appel à la méthode
createStatement de la classe Connection.
Voici l'exemple d'un ResultSet modifiable, de type sensible aux modifications faîtes par ailleurs
et que l'on peut parcourir dans tous les sens :
Connection c;
c = DriverManager.getConnection(url,"username","password");

Statement st = c.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);

ATTENTION : Certaines bases de données sont incapables de fournir des ResultSet avec de
telles caractéristiques. En cas de doute, il peut-être très utile de manipuler les méta-
données (Voir plus loin dans ce chap.) et notamment d'appeler les méthodes
supportsResultSetType et supportsResultSetConcurrency de la classe DatabaseMetaData.
COURS Java – Notions avancées

F. Parcourir un ResultSet
F.1. Les méthodes
Il existe plusieurs façons de parcourir un jeu d'enregistrements. Voici un tableau listant les
différentes méthodes permettant de naviguer dans un jeu d’enregistrements :

Method Summary
boolean absolute(int row)
Déplace le curseur à la ligne passée en paramètre
void afterLast()
Déplace le curseur à la fin de ce ResultSet , juste après la
dernière ligne.
void beforeFirst()
Déplace le curseur à la fin de ce c avant la première ligne
boolean first()
Déplace le curseur sur la première ligne
boolean isAfterLast()
Renvoie true si le curseur se situe après la dernière ligne.
boolean isBeforeFirst()
Renvoie true si le curseur se situe avant la première ligne.
boolean isFirst()
Renvoie true si le curseur se situe sur la première ligne
boolean isLast()
Renvoie true si le curseur se situe sur la dernière ligne
boolean last()
Déplace le curseur sur la dernière ligne
void moveToCurrentRow()
Déplace le curseur à la dernière position mémorisée du curseur. Il
s’agit habituellement de la ligne courante
void moveToInsertRow()
Déplace le curseur à la position d’insertion d’un nouvel
enregistrement
boolean next()
Déplace le curseur à la position suivante. Renvoie false si aucune
ligne ne suit la ligne courante
boolean previous()
Déplace le curseur à la position précédente. Renvoie false si
aucune ligne ne précède la ligne courante
boolean relative(int rows)
Déplace le curseur d’un nombre de lignes fourni en paramètre. Ce
COURS Java – Notions avancées

nombre peut-être positif ou négatif


void setFetchDirection(int direction)
Donne la direction dans laquelle les lignes doivent être parcourues
Liste Méthodes servant à parcourir un objet ResultSet

F.2. Exemple
Voici un exemple de programme capable de parcourir un objet ResultSet et d’afficher à l’écran
le champ nom d’une table nommée Clients :

try {
Class.forName("com.mysql.jdbc.Driver");

} catch (ClassNotFoundException ex) {


System.out.println("Pilote JDBC non enregistré");
}

String url = "jdbc:mysql://bd.diderot.org:3306/diderot";

try {
Connection c;
c = DriverManager.getConnection(url,"username","password");

Statement st = c.createStatement();

String strSql = "SELECT nom FROM clients"; Appel à la méthode next


ResultSet rs = st.executeQuery(strSql); comme condition de
continuation de la boucle
while (rs.next())
System.out.println(rs.getString("nom"));
Récupération et
} catch (SQLException ex) { affichage du contenu
System.out.println("Erreur SQL :"+ex.getMessage()); du champ nom
}

G. Insérer et modifier un ResultSet

Avant de modifier un ResultSet, il faut s’assurer que ce dernier est bien du type
CONCUR_UPDATABLE (Voir Caractéristiques d’un ResultSet).

G.1. Insérer
Avant d’insérer une ligne, il faut faire appel à la méthode moveToInsertRow(). Cette opération
revient à placer le curseur sur une ligne spéciale utilisée pour l’insertion uniquement.
rs.moveToInsertRow();
Ensuite, il faut mettre à jour les champs de la nouvelle ligne grâce aux méthodes updateXXX
ou XXX représente le type champ à mettre à jour :
rs.updateString(“nom”,”VALET”); // Met à jour le champ nom
COURS Java – Notions avancées

rs.updateString(2,”Génaël”); // Met à jour le 2ème champ


A ce stade , la base de données n’a pas encore été modifiée. Elle le sera à l’appel de cette
instruction :
rs.insertRow();

L’appel à la méthode insertRow() est équivalent à une requête SQL de type INSERT. Néanmoins,
il est plus judicieux d’utiliser les méthodes de ResultSet plutôt que les requêtes SQL. Ceci est
valable pour la version 2 de JDBC (Très utilisée aujourd’hui)

La dernière étape facultative consiste à repositionner le curseur à la position qu’il occupait


avant l’appel à la méthode moveToInsertRow() :
rs.moveToCurrentRow();

G.2. Modifier
Pour modifier une ligne, il suffit de positionner le curseur sur cette ligne et de faire des appels
successifs aux méthodes updateXXX.
Pour valider les changements dans la base de données, il convient d’utiliser la méthode
updateRow().
rs.updateString("nom","DUPONT");
rs.updateInt("age",35);
rs.updateRow();

H. Utilisation de requêtes pré-compilées


H.1. Introduction
Dans le sous-chapitre précédent, nous décrivions les objets PreparedStatement comme des
zones de description de requêtes pré-compilées qui offrent de meilleures performances que les
objets Statement traditionnels.

L’avantage de ces objets est qu’ils peuvent être exécutés avec des paramètres différents à
chaque exécution. Une requête pourra être executée plusieurs fois avec un seul objet
PreparedStatement.

H.2. Comment créer un objet PreparedStatement ?


Ce type d’objet est toujours associé à un objet Connection. En utilisant un objet Connection déjà
existant, nous écrirons le code suivant :
PreparedStatement updatePort = con.prepareStatement(
"UPDATE Clients SET port = ? WHERE ville LIKE ?");
COURS Java – Notions avancées

H.3. Exécuter avec des paramètres


La base de données est alors prête à exécuter les requêtes consistant à modifier le montant des
frais de port pour tous les clients habitant la ville de Paris :
updatePort.setDouble(1,6.0); // Frais de port à 6 euros
updatePort.setString(2, "Paris"); // Pour les clients habitants Paris

updatePort.executeUpdate(); // Mise à jour des données

Pour changer les frais de port pour tous les clients habitant la ville de Lyon, il suffit de réutiliser
la requête pre-compilée :
updatePort.setDouble(1,7.5);
updatePort.setString(2, "Lyon");

updatePort.executeUpdate();

H.4. Exécuter au sein d’une boucle


Imaginons que l’on souhaite modifier les frais de port pour un certain nombre de villes dont les
noms sont stockés dans un tableau. Les frais de port correspondant à chaque ville seront
stockées dans un autre tableau :
PreparedStatement updatePort = con.prepareStatement(
"UPDATE Clients SET port = ? WHERE ville LIKE ?");

String [] ville = {"Paris","Lyon","Bordeaux","Brest","Lille"};


double [] port = {6.0 , 7.5, 7.8, 8.0, 7.0 };

for (int i=0; i<ville.length ; i++) { Préparation du tableau


updatePort.setDouble(1,port[i]); contenant les villes
updatePort.setString(2,ville[i]);
updatePort.executeUpdate();
}
Modification des
paramètres de la
Exécution de la requête requête
à chaque passage dans
la boucle
COURS Java – Notions avancées

I. Les méta-données
I.1. Introduction
Dans les pages précédentes , nous sommes partis du constat que nous connaissions
parfaitement les types et les noms des champs présents dans la base de données. Parfois, il
peut-être utile d’avoir accès à certaines informations sur la structure et les types de données
d’une base.
Les méta-données contiennent donc des informations sur la structure de la base de données
(Les tables, les champs, …)
Toutes les bases de données n’autorisent pas l’utilisation des méta-données

I.2. DatabaseMetaData
Il s’agit d’une classe vous permettant d’obtenir un maximum d’informations sur la base de
données elle-même. Ces informations explorent toute la complexité des bases de données et
selon le type de base, tout ou partie de ces informations peuvent ne pas être disponibles.

Voici un programme qui extrait quelques informations à propos d’une base ACCESS en passant
par le pont JDBC/ODBC. Le programme utilise la classe Properties , qu’il convient de connaître
avant de se plonger dans le programme :

import java.sql.*;
import java.util.*;

public class MetaDonnees {


public static void main( String[] args) {
try {
// Enregistrement du pilote
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

// Etablissement de la connexion
Récupération d’un Connection c;
objet de type String url = "jdbc:odbc:cours3java";
DatabaseMetaData
nommé md c=DriverManager.getConnection(url);

// Obtention des meta-donnees


DatabaseMetaData md = c.getMetaData();

// Initialisation d'une liste de proprietes


Appel à la méthode Properties prop = new Properties();
de md informant sur
le nom du produit de // Acquiert les proprietes
base de données prop.setProperty("Nom du produit",
md.getDatabaseProductName());
prop.setProperty("Version du produit",
md.getDatabaseProductVersion() );
Conversion de prop.setProperty("Nombre max de connexions",
l’entier représentant String.valueOf(md.getMaxConnections()) );
le nombre max de prop.setProperty("Mots cles SQL",
connexions en une
chaine (String)
COURS Java – Notions avancées

md.getSQLKeywords() );
prop.setProperty("Supporte les procedures stockees",
String.valueOf(md.supportsStoredProcedures()));

prop.setProperty("Supporte les procedures stockees",


Envoie la liste de String.valueOf(md.supportsStoredProcedures()));
propriétés
directement à // Envoie la liste a l’ecran
l’écran. prop.list(System.out);

} catch ( ClassNotFoundException ex) {


System.out.println("Erreur de config :"
+ex.getMessage());
} catch ( SQLException ex) {
System.out.println("Erreur SQL :" +ex.getMessage());
}
}
}
Fichier MetaDonnees.java

I.3. ResultSetMetaData
Voyons maintenant comment obtenir des informations plus détaillées sur les objets ResutSet et
les lignes et colonnes qu’il contient. En effet, il peut-être très intéressant de connaître la taille
ou encore le type de données d’un champ avant d’y insérer des données.
Voici une liste des méthodes pouvant être utilisées pour obtenir des informations

Liste des méthodes de ResultSetMetaData


String getCatalogName(int column)
Donne le nom du catalogue auquel appartient la colonne spécifiée
String getColumnClassName(int column)
Renvoie le nom qualifié de la classe Java dont les instances seront renvoyées
lors de l’appel à la méthode getObject(…) de ResultSet. La méthode getObject(..)
peut-être appelée pour obtenir la valeur d’un champ sous forme d’objet Java
int getColumnCount()
Renvoie le nombre de champs (colonnes) de cet objet
int getColumnDisplaySize(int column)
Renvoie la taille maximale du champ dont le numéro de colonne est donné en
paramètres
String getColumnLabel(int column)
Renvoie le titre du champ désigné par le numéro de colonne, utilisé pour les
impressions ou les affichages.
String getColumnName(int column)
Renvoie le nom du champ.
int getColumnType(int column)
Renvoie le type SQL du champ spécifié. Les types SQL peuvent être obtenu en
COURS Java – Notions avancées

utilisant la classe java.sql.Types


String getColumnTypeName(int column)
Renvoie le type SQL du champ spécifié sous forme de chaîne de caractères.
int getPrecision(int column)
Renvoie le nombre de digits décimaux du champ spécifié
int getScale(int column)
Renvoie le nombre de digits après la virgule.
String getSchemaName(int column)
Renvoie le nom du schéma de table pour le champ spécifié
String getTableName(int column)
Renvoie le nom de la table
boolean isAutoIncrement(int column)
Indique si le champ spécifié est de type auto-increment et donc en lecture
seule.
boolean isCaseSensitive(int column)
Indique si le champ spécifié est sensible à la casse (majuscules/minuscules)
boolean isCurrency(int column)
Indique si la valeur du champ est type monétaire
boolean isDefinitelyWritable(int column)
Indique si une écriture sur la valeur de champ sera définitive
int isNullable(int column)
Indique la possibilité de trouver des valeurs nulles pour le champ spécifié
boolean isReadOnly(int column)
Indique si la valeur du champ est en lecture seule
boolean isSearchable(int column)
Indique si le champ spécifié peut faire partie d’une clause SQL WHERE.
boolean isSigned(int column)
Indique si le champ spécifié peut contenir un nombre signé
boolean isWritable(int column)
Indique si la valeur du champ spécifié peut-être écrite
Methodes de la classe ResultSetMetaData

Voici un extrait de programme permettant de vérifier la taille maximale d’une chaîne dans un
champ et de tronquer la chaîne à insérer en cas de dépassement :
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");

ResultSetMetaData rsmd = rs.getMetaData(); Récupération de la


int tailleMax = rsmd.getColumnDisplaySize(); taille maximum

String maChaine = "Chaine à inserer dans la BD" ;

if (tailleMax<maChaine.size()) Tronquage de la
maChaine = machaine.substring(1,tailleMax); chaîne si
dépassement
COURS Java – Notions avancées

rs.updateString("champ",maChaine);
rs.updateRow(); Mise à jour du champ
Mise à jour de la base
J. Transactions avec JDBC
J.1. Introduction
Lorsque l’on modifie les données d’une base, il est vital de maintenir une certaine cohérence
dans les données. Imaginons une base de données contenant toutes les informations
concernant les vols d’une compagnie aérienne. Pour supprimer un passager d’un vol en
particulier, il faut supprimer la ligne le concernant grâce à une requête de type DELETE. Il faut
également mettre à jour le nombre de sièges libres sur ce vol. Nous avons là deux opérations à
mener. Que se passera-t-il si la première opération qui consiste à supprimer le passager se
déroule bien mais que la mise à jour du nombre de sièges libres ne se fait pas ? Il y aura des
données corrompues dans la base.
Les transactions peuvent résoudre ce problème. Elles consistent à englober plusieurs
opérations dans un même sous-ensemble et de considérer que la transaction a abouti lorsque
toutes les opérations ont réussi. Si une des opérations échoue, alors, toutes les autres sont
également annulées.

J.2. Le mode « auto-commit »


Par défaut, toute connexion à une base de données est en mode « auto-commit ». Chaque
commande SQL (SQL Statement), est traité comme une transaction qui sera automatiquement
validée juste après avoir été executée.
En désactivant le mode « auto-commit » , vous considérez que tous les modifications ou ajouts
effectués par objets Statement crées à partir d’un objet Connection ne seront validés que lors
de l’appel à la méthode commit de Connection.
Voici un exemple illustrant ce qui vient d’être dit. Dans ce programme, il s’agit de supprimer un
passager d’un vol et d’incrémenter le nombre de places libres :

Désactivation des transactions


automatiques pour cette Requête SQL pour
connexion
con.setAutoCommit(false); effacer le
passager
Statement deletePassager = con.createStatement(
“DELETE FROM Passagers WHERE id=476”);
deletePassager.executeUpdate();

Statement volStmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE


,ResultSet.CONCUR_UPDATABLE);
String strSql = “SELECT * FROM vols WHERE id=’AF3456’ “);

ResultSet rs = volStmt.executeQuery(strSql);
int nbPassagers = rs.getInt(“nbPassagers”); Requête SQL pour
récupérer le vol à
rs.updateInt(“nbPassagers”,--nbPassager);
rs.updateRow(); modifier
Validation de
con.commit(); la Mise à jour du
transaction nombre de passagers
COURS Java – Notions avancées

con.setAutoCommit(true);

Activation des
J.3. Annuler une transaction
transactions
automatiques
Afin d’être absolument pour
sûr qu’aucune modifications de données n’a pu être validée, il est
cette connexion
préférable d’annuler une transaction lorsqu’une exception de type SQLException est générée.
Pour annuler une transaction , il suffit d’appeler la méthode roollback() de Connection. Il est
préférable d’appeler la méthode rollback() dans le cas où une des opérations vers la base de
données a provoqué une exception de type SQLException :

Connection conn = null;


try {
conn = DriverManager.getConnection(strUrl); Création de la connexion, du
conn.setAutoCommit(false); Statement et opérations sous le
CallableStatement = /* . . . */ regîme de la transaction

/* . . . */ Validation des opérations


précédentes Annulation de la transaction
conn.commit(); en cas d’erreur
} catch(SQLException e) {
conn.rollback();
} finally {
conn.close(); /* Fermeture de la connexion */
}

Notez que les méthodes rollback() et commit() sont également susceptibles de provoquer une
exception. Pour une fiabilité maximum, certains développeurs insèrent l’appel à rollback() à
l’intérieur d’un bloc try…catch . L’imbrication de bloc try…catch étant accepté en Java, il devient
alors possible d’empêcher une perte des données au cas où la méthode rollback() échouerait.

J.4. Niveaux de transactions


Par défaut, la base de données fixe le niveau de transaction. Avec JDBC, il existe plusieurs
niveaux de transactions mais tous ne sont pas forcément pris en charge. Pour savoir quel est le
niveau par défaut de votre SGBD, il suffit d’appeler la méthode getTransactionIsolation() qui
renvoie un entier dont la signification est décrite plus bas.

A l’inverse, la méthode setTransactionIsolation(int level) de la classe Connection permet de


modifier le niveau de transaction. Elle prend comme arguments les valeurs suivantes, champ
statique de cette même classe :
 TRANSACTION_READ_UNCOMMITED : une opération t1 modifie des
données, alors l’opération t2 qui suit pourra lire ces données modifiées.
 TRANSACTION_READ_COMMITTED : une opération t1 modifie des
données , alors l’opération t2 ne pourra pas lire les données modifiées.
 TRANSACTION_REPEATABLE_READ : une opération t1 lit des données,
alors que l’opération t2 modifie ces données. Si t1 lit à nouveau ces données, il lit
la même valeur que précedemment.
COURS Java – Notions avancées

 TRANSACTION_SERIALIZABLE : t1 lit un ensemble de données, t2 ajoute


des données à cet ensemble, si t1 lit à nouveau l’ensemble, il ne verra pas les
données modifiées. Les opérations apparaissent comme si elles avaient été
exécutées en séquence.
COURS Java – Notions avancées

A H
accept, 39 HTML, 39
activeCount Voir Threads HTTP, 33, 39, 44
ANSI, 4 HttpURLConnection, 45
B I
BufferedInputStream, 7 InetAddress, 34, 36
BufferedReader, 12, 34, 39 InputStream, 4
read, 5
C
InputStreamReader, 8, 12, 34, 40
CallableStatement, 56 insertRow, 63
catch, 10 interrupt, 20
Class, 54 InterruptedIOException, 35
closeEntry, 12 IOException, 11, 36
commit, 69, 70 isAlive, 20
CONCUR_UPDATABLE, 61
J
connect, 45
coopératif Voir Multitâche java.sql, 53
createStatement, 60, 61 java.util.zip, 12
join, 35
D
L
DatagramPacket, 32
DatagramSocket, 32 line.separator, 10
DataInputStream, 6
M
read, 6
readBoolean, 6 MAX_PRIORITY, 21
readByte, 6 MIN_PRIORITY, 21
readChar, 6 moveToCurrentRow, 64
readDouble, 6 moveToInsertRow, 63
DriverManager, 51 Multitâche, 16
coopératif, 16
E
préemptif, 16
executeQuery, 56, 59
N
executeUpdate, 65
NORMAL_PRIORITY, 21
F
notify, 29
File, 6 notifyAll, 29
FileInputStream, 6
O
FileNotFoundException, 11
FileReader, 9 openConnection, 44
FileWriter, 9 openSocket, 36
forName, 54 openStream, 44
FORWARD_ONLY, 60 OSI, 31
FTP, 31, 33, 44 OutputStream, 4
write, 5
G
P
GET, 47
getAllByName, 37 passerelle JDBC/ODBC, 53
getBytes, 36 POP3, 32
POST, 47
getConnection, 55 préemptif, 16
getHeaderFieldKey, 46 PreparedStatement, 55, 65
getInputStream, 34, 47 PrintStream, 4
getNextEntry, 12 PrintWriter, 9, 40
getOutputStream, 34 processus Voir Threads
getProperty, 10 Properties
GZIPInputStream, 4 setProperty, 66
COURS Java – Notions avancées

R Writer, 4, 8
read Voir InputStream Z
Reader, 4, 8
ZipEntry, 12
ResultSet, 62, 68
ZipInputStream, 7, 12
ResultSetMetaData, 67, 68
ZIPInputStream, 4
RFC, 44
rollback, 70
Runnable, 17, 18, 35
S
Server, 32
ServerSocket, 32, 39, 42
setAutoCommit, 69, 70
setDoInput, 45
setDoOutput, 45
setIfModifiedSince, 45
setSoTimeout, 35
setUseCaches, 45
sleep, 18, 19
SMTP, 32
Socket, 33
sockets, 33
SQLException, 70
Statement, 55, 56, 61
supportsResultSetConcurrency, 61
supportsResultSetType, 61
suspend, 19
synchronised, 28
System, 9
T
TCP, 31
telnet, 41
thread, 17
Thread, 16, 17
ThreadGroup, 27
Threads
activeCount, 27
processus, 16
Transactions, 70
TRANSACTION_READ_COMMITTED, 70
TRANSACTION_READ_UNCOMMITED, 70
TRANSACTION_REPEATABLE_READ, 70
TRANSACTION_SERIALIZABLE, 70
try, 10
TYPE_SCROLL_INSENSITIVE, 60
TYPE_SCROLL_SENSITIVE, 60, 61
U
UDP, 31
UNICODE, 8
updateRow, 68
updateString, 68
URL, 54
URLConnection, 32, 45
URLEncoder, 32
user.dir, 11
W
wait, 19, 29
COURS Java – Notions avancées Version 2.4 - Mai 2003

Java – Notions avancées - G.VALET – Reproduction interdite 78 / 78

Vous aimerez peut-être aussi