You are on page 1of 235

L’atelier de développement JAVA

L’atelier de développement JAVA

L’atelier de développement JAVA

L’atelier de développement JAVA

L’atelier de développement JAVA

Projet : Projet : Projet : Projet : Projet :


L’atelier de develop- L’atelier de develop- L’atelier de develop- L’atelier de develop- L’atelier de develop-
pement JAVA pement JAVA pement JAVA pement JAVA pement JAVA

Client : Client : Client : Client : Client :


Sun Service Forma- Sun Service Forma- Sun Service Forma- Sun Service Forma- Sun Service Forma-
tion tion tion tion tion

Réf. Sun : Réf. Sun : Réf. Sun : Réf. Sun : Réf. Sun :
LJ300 LJ300 LJ300 LJ300 LJ300

Révision : D Révision : D Révision : D Révision : D Révision : D

Date : 20/7/98 Date : 20/7/98 Date : 20/7/98 Date : 20/7/98 Date : 20/7/98

Sun Sun Sun Sun Sun


Microsystems Microsystems Microsystems Microsystems Microsystems
L’atelier de développement JAVA
L’atelier de développement JAVA

L’atelier de développement JAVA

Projet : L’atelier de develop- Projet : L’atelier de develop- Projet : L’atelier de develop-


pement JAVA pement JAVA pement JAVA
Client : Sun Service Formation Client : Sun Service Formation Client : Sun Service Formation
Réf. Sun : LJ300 Réf. Sun : LJ300 Réf. Sun : LJ300

Révision : D Révision : D Révision : D


Date : 20/7/98 Date : 20/7/98 Date : 20/7/98

Sun Microsystems France Sun Microsystems France Sun Microsystems France


L’atelier de développement JAVA

Intitulé Cours : L’atelier de developpement JAVA


Client : Sun Service Formation
Réf. Sun : LJ300
Sun Microsystems France S.A.
Service Formation
143 bis, avenue de Verdun Révision : D
92442 ISSY LES MOULINEAUX Cedex Date : 20/7/98
Tel 01 41 33 17 17
Fax 01 41 33 17 20
Sun Microsystems France
Protections Juridiques

 1998 Sun Microsystems, Inc.


2550 Garcia Avenue, Mountain View, California 94043-1100 U.S.A.

AVERTISSEMENT
Ce produit ou document est protégé par un copyright et distribué avec des licences qui en restreignent l’utilisation, la
copie, la distribution, et la décompilation. Aucune partie de ce produit ou de sa documentation associée ne peut être
reproduite sous aucune forme, par quelque moyen que ce soit, sans l’autorisation préalable et écrite de Sun et de ses
bailleurs de licence, s’il y en a.
Des parties de ce produit pourront être dérivées du système UNIX® licencié par Novell, Inc. et du système Berkeley 4.3
BSD licencié par l’Université de Californie. UNIX est une marque enregistrée aux Etats-Unis et dans d’autres pays et
licenciée exclusivement par X/Open Company Ltd. Le logiciel détenu par des tiers, et qui comprend la technologie
relative aux polices de caractères, est protégé par un copyright et licencié par des fournisseurs de Sun.
Sun, Sun Microsystems, le logo Sun, sont des marques déposées ou enregistrées de Sun Microsystems, Inc. aux Etats-Unis et
dans d’autres pays. Toutes les marques SPARC, utilisées sous licence, sont des marques déposées ou enregistrées de SPARC
International, Inc. aux Etats-Unis et dans d’autres pays. Les produits portant les marques SPARC sont basés sur une
architecture développée par Sun Microsystems, Inc.
Les interfaces d’utilisation graphique OPEN LOOK® et Sun™ ont été développées par Sun Microsystems, Inc. pour ses
utilisateurs et licenciés. Sun reconnaît les efforts de pionniers de Xerox pour la recherche et le développement du concept
des interfaces d’utilisation visuelle ou graphique pour l’industrie de l’informatique. Sun détient une licence non exclusive
de Xerox sur l’interface d’utilisation graphique Xerox, cette licence couvrant aussi les licenciés de Sun qui mettent en
place l’interface d’utilisation graphique OPEN LOOK et qui en outre se conforment aux licences écrites de Sun.
Le système X Window est un produit de X Consortium, Inc.
CETTE PUBLICATION EST FOURNIE “EN L’ETAT” SANS GARANTIE D’AUCUNE SORTE, NI EXPRESSE NI
IMPLICITE, Y COMPRIS, ET SANS QUE CETTE LISTE NE SOIT LIMITATIVE, DES GARANTIES CONCERNANT LA
VALEUR MARCHANDE, L’APTITUDE DES PRODUITS A RÉPONDRE A UNE UTILISATION PARTICULIERE, OU LE
FAIT QU’ILS NE SOIENT PAS CONTREFAISANTS DE PRODUITS DE TIERS.

Protections Juridiques 7
Intutilé Cours : L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
Table des matières

Prérequis............................................................................................... ii
Objectifs du cours............................................................................... iii
Projet : Le poste de travail d’un courtier en bourse ....................... 2
Généralités ................................................................................... 2
Exposé du problème ................................................................... 2
Le système existant ..................................................................... 2
Le système existant (suite) ......................................................... 3
Spécifications (suite) ................................................................... 4
Configuration de la base : ................................................. 4
Spécifications générales ............................................................. 5
Fonctionnalités principales :............................................. 5
Limitations ................................................................................... 6
PHASE 1 : l’architecture générale..................................................... 7
PHASE 2 : l’accès à la base................................................................. 9
PHASE 3 : l’interaction utilisateur.................................................. 11
PHASE 4 : assemblage d’un produit complet............................... 13
PHASE 5 : consolidations, extensions............................................ 15
Objectifs ...................................................................................... 17
Références .................................................................................. 17
Introduction à mSQL ....................................................................... 18
Généralités ................................................................................. 18
la réalisation de mSQL ............................................................ 19
Les outils de mSQL ................................................................... 19
............................................................................................ 19
............................................................................................ 19
msqld – le moteur mSQL.......................................... 19
les outils mSQL (suite) ............................................................ 20
relshow - Visualiseur de schéma mSQL ....................... 20
msqladmin – administration de la base (pour mémoire)
20
msqldump – image de la base (pour mémoire) ......... 20
Contrôle d’accès mSQL (pour mémoire) ....................................... 21
les outils mSQL (suite) ............................................................ 23

viii

Copyright 1998 Sun Microsystems, Inc. Tous droits réservés. SunService Avril 98
Commandes mSQL........................................................................... 24
Généralités ................................................................................. 24
La requête SELECT ................................................................. 25
La requête SELECT (suite)...................................................... 26
Exemples ........................................................................... 26
La requête SELECT (suite)...................................................... 27
Jointures............................................................................. 27
La commande INSERT ............................................................. 28
La commande DELETE ........................................................... 28
La commande UPDATE........................................................... 29
La commande CREATE (pour mémoire) .............................. 30
La commande DROP (pour mémoire) ................................... 30
Exercices ............................................................................................. 31
Introduction ....................................................................................... 34
“Pilote” JDBC..................................................................................... 35
Organigramme JDBC........................................................................ 37
L’enchainement des appels ..................................................... 37
Package java.sql ................................................................... 37
Organigramme JDBC........................................................................ 38
Exemple JDBC ................................................................................... 39
Création de pilotes JDBC ................................................................. 41
Création explicite d’une instance de pilote JDBC ................ 41
Pilotes JDBC ....................................................................................... 43
Désignation d’une base de données....................................... 43
Connexion à une base de données.......................................... 44
Interrogation d’une base de données..................................... 45
Instructions JDBC.............................................................................. 46
Soumission d’une requête........................................................ 46
requête préparée (non disponible sous mSQL) .................... 47
Exemple ...................................................................................... 47
Les méthodes setXXX ............................................................... 47
Méthodes setXXX ........................................................................... 48
procédure stockée (non disponible sous mSQL).................. 49
Exemple ...................................................................................... 50
Appel de procédure .................................................................. 50
Récupération de résultats ........................................................ 51
Méthodes getXXX ........................................................................... 53
Correspondance des types de données SQL en Java ................... 54
Utilisation de l’API JDBC................................................................. 55
Types de conception des pilotes JDBC .................................. 55
Types d’architecture d’accès aux bases de données .................... 56
Conceptions en deux niveaux ................................................. 56
Conceptions en trois niveaux .................................................. 57
Applets................................................................................................ 58
Applets et applications de bases de données traditionnelles .
58

ix L’atelier de développement JAVA

Copyright 1998 Sun Microsystems, Inc. Tous droits réservés. SunService Avril 98
Performances ............................................................................. 58
Contraintes de sécurité............................................................. 59
Accès au manipulations graphiques .............................................. 62
Le package AWT ....................................................................... 62
Les gestionnaires de Disposition (LayoutManager) .................... 63
Les événements ................................................................................. 65
Evénements sources.................................................................. 65
Traitements d’événements....................................................... 65
Modèle de délégation (JDK 1.1) .............................................. 66
Comportement de l’interface graphique utilisateur Java............ 70
Catégories d’événements ......................................................... 70
Tableaux ............................................................................................. 71
Comportement de l’interface graphique utilisateur Java............ 72
Evénements générés par composants AWT.......................... 72
Obtention d’informations sur un événement ....................... 73
Récepteurs multiples ................................................................ 73
Adaptateurs d’événements.............................................................. 74
Button.......................................................................................... 76
List....................................................................................................... 80
TextArea ............................................................................................. 83
TextComponent......................................................................... 84
Frame .................................................................................................. 85
Panel.................................................................................................... 86
Dialog.................................................................................................. 87
FileDialog ........................................................................................... 89
ScrollPane........................................................................................... 90
Menus ................................................................................................. 91
Menu Aide ................................................................................. 91
MenuBar ............................................................................................. 92
Menu ................................................................................................... 93
MenuItem ........................................................................................... 94
CheckboxMenuItem ......................................................................... 95
PopupMenu ....................................................................................... 96
Contrôle des aspects visuels............................................................ 98
Couleurs ..................................................................................... 98
Polices ......................................................................................... 99
Polices ....................................................................................... 100
Impression........................................................................................ 101
E/S JAVA : concepts fondamentaux............................................ 104
flots d’E/S (Streams)............................................................... 104
I/O Streams et Reader/Writer.............................................. 105
catégories de flots.................................................................... 105
filtres ......................................................................................... 106
Fichiers.............................................................................................. 107
Noms de fichiers ............................................................ 107
Tests de fichiers ............................................................. 107

table des matières x

Copyright 1998 Sun Microsystems, Inc. Tous droits réservés. SunService Avril 98
Information générale axée sur les fichiers et utilitaires.
107
Utilitaires en rapport avec les répertoires .................. 107
Linéarisation .................................................................................... 108
Classes DataInputStream et DataOutputStream..... 108
Méthodes DataInputStream ......................................... 108
Object Input/Output .............................................................. 109
Architecture de linéarisation ......................................................... 110
Package java.io ........................................................................ 110
Interface Serializable ....................................................... 111
Eléments sérialisables............................................................. 111
Ecriture et lecture d’un flot d’objets ............................................. 112
Lecture ...................................................................................... 112
qu’est ce qui est transferré? ................................................... 113
personnalisation de la lecture/écriture d’objet .................. 114
Externalisable........................................................................... 115
Programmation réseau sous Java ................................................. 118
Sockets ...................................................................................... 118
Le modèle réseau de Java............................................................... 119
Principe d’un Serveur TCP/IP...................................................... 120
Exemple de code de mise en oeuvre d’un serveur TCP/IP
120
Principe d’un Client TCP/IP......................................................... 121
échanges UDP................................................................................. 122
Exemple de Serveur UDP ............................................................. 123
Exemple de client UDP ................................................................ 124
UDP en diffusion (Multicast) ..................................................... 125
Exemple de Serveur Multicast ..................................................... 126
Exemple de client Multicast .......................................................... 127
Fonction de l’architecture RMI en Java........................................ 131
Packages et hiérarchies RMI.......................................................... 132
Package java.rmi ................................................................. 132
Création d’une application RMI ................................................... 135
Exemple bancaire .................................................................... 135
Création d’une application RMI ................................................... 136
Interfaces bancaires................................................................. 136
Procédure ................................................................................. 138
Interface Account .................................................................. 139
Interface AccountManager................................................... 140
réalisation de l’interface Account — AccountImpl .......... 141
AccountManagerImpl............................................................ 143
Classe de conteneurs ..................................................... 145
Compilation du code .............................................................. 146
Utilisation de la commande rmic......................................... 147
Application BankServer ...................................................... 148
Application rmiregistry.................................................... 150

xi L’atelier de développement JAVA

Copyright 1998 Sun Microsystems, Inc. Tous droits réservés. SunService Avril 98
Application BankClient ...................................................... 151
Exécution de l’application BankClient .............................. 154
Syntaxe............................................................................. 155
Exemples ......................................................................... 155
Sécurité RMI..................................................................................... 156
Chargement de classe ............................................................. 156
Côté serveur RMI ........................................................... 156
Côté client RMI............................................................... 157
Invocation RMI au travers d’un coupe-feu ......................... 157
Pourquoi réaliser du code natif?................................................... 160
un exemple : "Hello World" en C.................................................. 161
résumé des phases : ................................................................ 161
Ecriture du code JAVA :................................................ 161
Création des binaires JAVA de référence : ................ 161
Génération du fichier d’inclusion C/C++ :................ 161
Ecriture du code natif : ................................................ 161
Création d’une librairie dynamique:.......................... 161
Exécution: ........................................................................ 161
Ecriture du code JAVA........................................................... 162
Création des binaires JAVA de référence ............................ 163
Génération du fichier d’inclusion C/C++........................... 164
Ecriture du code natif ............................................................. 165
Création d’une librairie dynamique..................................... 166
Exécution .................................................................................. 167
présentation de JNI ......................................................................... 168
JNI: types, accès aux membres, création d’objets....................... 169
références sur des objets JAVA: .................................................... 172
exceptions......................................................................................... 173
invocation de JAVA dans du C..................................................... 174
Organisation des packages et des répertoires............................. 176
convention de codage..................................................................... 177
Identificateurs (conventions standard)................................ 177
Identificateurs (conseils complémentaires)......................... 177
Nommage (conseils complémentaires)................................ 178
Mise en page ............................................................................ 179
portabilité ......................................................................................... 180
performances ................................................................................... 181
traces, exceptions ........................................................................... 182
le "bon " et le "beau" code ?............................................................ 183
les interactions graphiques ............................................................ 187
répartition......................................................................................... 188
les protocoles ........................................................................... 189
internationalisation......................................................................... 190
intégration des méthodes natives ................................................. 191
introduction : R.A.D et/ou maîtrise du code de base?.............. 194
L’intégration des outils, les ateliers .............................................. 196

table des matières xii

Copyright 1998 Sun Microsystems, Inc. Tous droits réservés. SunService Avril 98
analyse et conception...................................................................... 197
L’éditeur ........................................................................................... 198
Outils annexes à l’éditeur .............................................................. 199
L’aide à la conception d’interaction ............................................. 200
Gestion des sources......................................................................... 201
principes ................................................................................... 201
outils.......................................................................................... 201
points ........................................................................................ 202
Gestionnaires de maintenance ...................................................... 203
Documentation de code, aide en ligne........................................ 204
Debug................................................................................................ 205
outils.......................................................................................... 205
génération (make) ........................................................................... 206
tests.................................................................................................... 207
principes ................................................................................... 207
produits .................................................................................... 207
points ........................................................................................ 208
analyse de couverture .................................................................... 209
analyses de performances.............................................................. 210
principes ................................................................................... 210
outils.......................................................................................... 210
points ........................................................................................ 210
Analyses statiques du code ........................................................... 211
principes ................................................................................... 211
outils.......................................................................................... 211
points ........................................................................................ 211
préparation à la livraison ............................................................... 212
livraison/déploiement ................................................................... 213
autres outils...................................................................................... 214
décompilateurs/brouilleurs .................................................. 214
outils syntaxiques.................................................................... 214
JavaWorkshop: Gestionnaire de projets ...................................... 216
Mise en oeuvre du “Project Manager”................................. 216
créer ou importer un portefeuille ......................................... 217
créer ou importer un projet ................................................... 217
fixer les attributs d’un projet ................................................. 218
JavaWorkshop: édition, compilation, tests.................................. 219
édition ....................................................................................... 219
personnalisation de l’édition ................................................. 219
contrôle d’accès et version ..................................................... 219
compilation .............................................................................. 220
test ............................................................................................. 220

xiii L’atelier de développement JAVA

Copyright 1998 Sun Microsystems, Inc. Tous droits réservés. SunService Avril 98
Introduction

Durant ce stage vous aurez la possibilité de mener à bien un projet


JAVA complet.

L’accent est mis sur la pratique et vous êtes vivement encouragé à


confronter vos reflexions à celles des autres stagaires (ou à celles de
l’animateur).

Ce stage contient peu de cours théoriques mais, selon vos besoins,


l’animateur peut-être amené à faire quelques rappels rapides -en règle
générale vous vous appuierez plutôt sur les aide-mémoires du
support-

Vous trouverez dans le présent support:

● La description générale du projet à réaliser.

● Une série d’aide-mémoires concernant l’utilisation de SQL, JDBC,


AWT, les entrées-sorties, la programmation réseau et RMI. Un
cours sur l’intégration de méthodes natives complète ces rappels.

● Deux chapitres constituant une introduction à la pratique


professionnelle du développement en JAVA : les savoir-faires et la
filière des outils.

i
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. SunService 1998
Prérequis

Pour participer à ce cours il est vivement conseillé de maitriser:

● Le contenu des cours LJ20 (introduction à Java) et LJ21


(programmation Java avancée) et en particulier:

● Les Api Java standard

● La création d’interface graphiques réalisées avec AWT.

● La programmation des sockets TCP/IP avec Java

● La programmation parallèle (Threads)

● Les techniques de programmation Objet

Introduction Revision D -ii


Copyright 1998 Sun Microsystems, Inc. Tous droits réservés.
Objectifs du cours

A la suite de ce cours vous serez capable de:

● d’initier un projet JAVA depuis la conception jusqu’à la réalisation


et aux tests.

● organiser les développements JAVA dans le cadre d’une filière


professionnelle.

● mettre en place une filière de maintenance

● enrichir en permanence vos savoir-faires en JAVA moyennant des


investissements modiques dans la veille technologique.

Introduction Revision D -iii


Copyright 1998 Sun Microsystems, Inc. Tous droits réservés.
Introduction Revision D -iv
Copyright 1998 Sun Microsystems, Inc. Tous droits réservés.
Le Projet 1

Objectifs
Ce chapitre décrit:

• Les spécifications générales du projet à réaliser durant le stage

• Les différentes phases de réalisation du code.

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
Projet : Le poste de travail d’un courtier en bourse

Généralités
L’exposé du problème ne définit pas toutes les spécifications (on retrouve
ici une situation courante dans la vie réelle!). Quelques précisions
supplémentaires seront données par l’animateur dans les présentations
de phases . Il faudra donc réfléchir à des spécifications plus détaillées, en
discuter en équipe et prendre des décisions définitives en accord avec les
orientations que fixera l’animateur.

Exposé du problème
Une société de courtage en bourse a commencé à réaliser une application
pour la saisie d’ordres de bourse. Pour différentes raisons il y a eu un
début de réalisation et l’équipe que vous allez constituer doit tenir compte
du système existant.

Le système existant
La société va déployer son application sur son réseau local sécurisé
(vision "intranet")

Vous disposez des composants suivants :

• Une base de données relationnelle. Le schéma de la base est déjà


défini. Pour les besoins de ce stage on opérera sur Mini-SQL
(mSQL) une petite base de données du domaine public -toutefois
le projet sera adaptable à d’autres bases-

• Un processus permanent de mise à jour de la cotation des valeurs.


Ce processus est censé fournir les évolutions de la cote en temps
réel. Pour les besoins du projet il s’agit d’un programme JAVA qui
est fourni.

• Un serveur HTTP

Le Projet 1/2
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1

Le système existant (suite)


Quelques informations complémentaires:

• La base de données, le serveur de cotations et le serveur HTTP


"tournent" sur un seul serveur Sun.

• Base mSQL:

• Le schéma est prédéfini et ne peut être changé

• Le processus mSQL sert les requêtes sur le port 1112 en


protocole TCP/IP .

• L’application de mise à jour de la cote est un programme JAVA


fourni :

• La cotation évolue toute les 45 secondes

• Toute modification doit être reportée dans la base de données.

• La manière dont les informations seront diffusées aux clients


reste à arréter. Si l’initiative des demandes de mises à jour reste
aux clients on utilisera alors un serveur écoutant sur le port
5432.

• serveur HTTP :

• écoute sur le port standard (80).

• les fichiers HTML seront disponibles sur le serveur dans un


répertoire accessible aux différentes équipes de
développement..

Le Projet 1/3
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
Le poste de travail d’un courtier en bourse

Spécifications (suite)

Configuration de la base :

La base existante, StockMarket, est configurée selon le schéma suivant:

Customer Table

Field Name Type Comment

ssn char (15) clef primaire


cust_name char (40)
address char (100)

Shares Table

Field Name Type Comment

ssn char (15) Not null


symbol char (8) Not null
quantity int

Stock Table

Field Name Type Comment

symbol char (8) clef primaire


price real

Le Projet 1/4
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
Le poste de travail d’un courtier en bourse

Spécifications générales
L’outil à développer en JAVA doit être un système opérant en mode
client/serveur permettant de mettre à jour les informations contenues
dans la base de données.

Fonctionnalités principales :

• Permettre au courtier("l’utilisateur") d’ajouter ou de supprimer un


client dans la base.
Il est admis que le nombre de clients dans la base peut être très
important.

• Permettre de modifier le nom ou l’adresse d’un client (mais pas


son identifiant unique -ssn-).

• Permettre de visualiser la cotation courante d’une ou de plusieurs


valeurs. Les valeurs changeant en permanence on étudiera la
manière la plus appropriée de porter ces modifications à la
connaissance de l’opérateur.
Il est admis que le nombre de valeurs de la cote est très limité (tout
au plus quelques centaines).

• Permettre d’acheter et de vendre des actions pour un client. La


base de données et l’interface homme/machine doivent être mises
à jour en conséquence. On devra pouvoir visualiser le portefeuille
du client et le modifier.

Des spécifications complémentaires devront être arrétées au cours du


projet. On simulera ainsi les nécessaires évolutions du projet au fur et
mesure que les besoins s’affineront (bien entendu ces évolutions devront
rester dans les limites raisonnables du temps qui est imparti!)

Le Projet 1/5
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
Le poste de travail d’un courtier en bourse

Limitations
Du fait de limitations importantes dans le temps on s’efforcera de
simplifier certains aspects du projet.

Ainsi on peut admettre que :

• Les requêtes concernant les clients utiliseront leur identifiant


unique(ssn), alors qu’il semblerait plus normal de les rechercher
par leur nom (et même par leur nom approximatif!).

• Idem pour les valeurs de la cote qui ne seront connues que par
leur code (symbol).

• On utilisera essentiellement des composants graphiques fournis


(AWT standard, JFC) des adaptations de ces composants sont
toutefois possibles.

Le Projet 1/6
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
PHASE 1 : l’architecture générale

principes
Déterminer l’architecture générale du projet.

Cette définition s’appuie sur les principes suivants :

• Un produit peut être décomposé en quelques grands composants


qui collaborent entre eux pour rendre le service attendu.

• Ces composants principaux communiquent entre eux au moyen


d’un protocole minimum (une A.P.I.). Il est important de définir
ces protocoles car ils permettent de réaliser une architecture
adaptable et un développement incrémental basé sur la définition
de "services" abstraits.
Un exemple :

• Une demande de mise à jour de la base peut provenir d’une


interface utilisateur interactive, d’une interface utilisateur
simplifiée en mode texte, d’une requête provenant d’une ligne
de communication distante, etc.
• Abstraire ces diverses possibilités dans un seul concept (une
interface JAVA par exemple) permet de faire fonctionner les
requêtes à la base dans différentes situations :
- On peut ainsi valider les interrogations à la base sans
attendre la réalisation de l’interface interactive,
- On peut tester cette base à l’aide de scenarios contenus dans
des fichiers textes,
- On peut transformer un produit dans lequel l’interface et
l’interrogation à la base fonctionnent dans le même processus
en un produit dans lequel ces deux fonctions communiquent
au travers du réseau (l’interrogation à la base se fait sur le
serveur, l’interface utilisateur est sur un client distant),
- etc.

Le Projet 1/7
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
réalisation
1. Former les équipes de développement

2. Au sein des équipes discuter de l’architecture générale, puis


définir d’une part les classes principales (ex. : "Client", "Valeur"
pour une valeur de la cote, "Portefeuille" pour décrire le
portefeuille d’un Client) et d’autre part décrire les grands
composants (en décrivant les méthodes d’API qui les caractérisent)

3. Proposer une politique générale pour le traitement des traces et


des Exceptions.

4. Obtenir un accord entre les équipes pour que les méthodes d’API
soient communes (objectif: un composant réalisé par une équipe
doit pouvoir être utilisé par l’autre).

5. Organiser les premiers "packages" de développement et coder les


définitions qui seront nécessaires pour la suite du projet.

6. Noter les interrogations sur la suite du projet, les différentes


options que l’on peut entrevoir, etc.

références
voir chapitres :

• recommandations de programmation : packages, convention de


codage, traces et exceptions.
La conception générale (UML) sort du cadre du présent cours.

• outils : les outils d’analyse et de conception sortent du cadre de


ce cours

Le Projet 1/8
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
PHASE 2 : l’accès à la base

principes
Réaliser le module d’interrogation de la base de données au travers de
JDBC.

Ce module sera testé à l’aide d’une interface très simplifiée lisant des
requêtes en mode texte sur l’entrée standard.

réalisation
1. Eventuellement, remise à jour des connaissances sur SQL et JDBC

2. Finaliser la mise en place de l’environnement de développement.


(commencer à utiliser JavaWorkshop)

3. Réaliser le ou les modules implantant les méthodes d’interrogation


de la base.
Documenter ces modules (javadoc)

4. Réaliser un module permettant de tester simplement la réalisation


précédente par de simples requêtes sous forme texte. Tester l’effet
sur la base en réalisant des requêtes SQL sur msql.

5. Tester simplement les mécanismes d’exceptions.

6. Donner quelques exemples de spécifications fonctionnelles


complémentaires qui permettront de tester votre API (c.a.d.
quelques règles implicites que l’API doit aussi vérifier).
Si l’on dispose de l’outil JAVASPEC (et d’un peu de temps) essayer
d’implanter ces règles et de les appliquer au module d’accès à la
base de données.

Le Projet 1/9
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
références
voir chapitres :

• rappels: SQL, JDBC, Entrées/Sorties

• recommandations de programmation : portabilité (100% java)

• outils : JavaWorkShop, mSQL, JAVASPEC

Le Projet 1/10
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
PHASE 3 : l’interaction utilisateur

principes
Maquette graphique : concevoir et réaliser une première version
d’interface utilisateur.
En tenant compte des principes de conception d’une interface
ergonomique concevoir une interface qui permette à l’opérateur de:

• rechercher la description d’un client

• créer, détruire ou modifier la description d’un client

• visualiser le portefeuille d’un client

• modifier le portefeuille d’un client par achat, vente d’un certain


nombre d’actions (prévoir option "tout vendre" correspondant
à une action donnée).

• visualiser les cours d’une ou plusieurs Valeurs de la cote.


(s’organiser éventuellement pour faire ressortir
automatiquement certaines valeurs).

réalisation
1. Eventuellement, remise à jour des connaissances sur les
composants, la disposition AWT, la gestion des événements
graphiques.

2. Faire un "design" général sur papier, l’affiner en codant des parties


de cette interface. Se répartir éventuellement le travail entre les
membres de l’équipe.
Tenir compte, pour le choix des composants, des limites
éventuelles (nombre de clients, nombre de valeurs à la cote).
Tenir compte également des besoins de personnalisation (taille des
police, disposition de certains champs, accélérateurs)

3. Réaliser une interface d’ensemble, l’assembler en local avec le


module d’interrogation de la base et avec le module de mise à jour
des valeurs.
Tester le fonctionnement et le faire tester par un "naïf" (un membre
d’une autre équipe).

Le Projet 1/11
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
4. Tester avec des conditions erronées (analyser la mise en oeuvre
des mécanismes de récupération d’exceptions et leur effet sur
l’interface utilisateur).

5. Envisager des modifications du type : exploitation dans un


contexte d’Applet, ajout de fonctions ( identification de
l’opérateur, demande d’impression) , modifications du contenu
des tables de la base de données, améliorations cosmétiques
(couleurs, image de fond), personnalisations .
En tirer des indications sur l’organisation du code et sa
maintenabilité.

références
voir chapitres :

• rappels: composants graphiques

• recommandations de programmation : les interactions


graphiques, le "bon" et le "beau" code : pratique AWT,
internationalisation

• outils : JavaWorkShop

Le Projet 1/12
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
PHASE 4 : assemblage d’un produit complet

principes
Mise en service dans des conditions réelles.
Répartition de l’application :

• Le processus de mise jour des cotations doit fonctionner de


manière autonome. (Dans la phase précédente il était lié à
l’application pour les besoins du test).

• Mise en oeuvre d’une application en mode client/serveur.


L’interface utilisateur ne fonctionne plus forcément sur le
serveur lui-même.

réalisation
1. Eventuellement, remise à jour des connaissances sur Sockets,
Threads, DataInput/OutPut, Serialisation, RMI

2. Discuter des différentes possibilités de réalisation pour la mise à


jour des valeurs de la cote sur les postes clients (initiative du
serveur, initiative du client).

3. Réaliser cette mise jour automatique et intégrer d’éventuelles


modifications de l’interface utilisateur.

4. Spécifier la réalisation du client déporté et justifier vos choix


(application autonome ou Applet, dialogue par Socket ou RMI,...)

5. Réaliser le client déporté et le mettre en oeuvre (ressources, fichier


HTML dans le cas d’une Applet, etc.)

6. Tester l’ interface en faisant intervenir les règles fonctionnelles


complémentaires définies en phase 2.

Le Projet 1/13
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
références
voir chapitres :

• rappels: E/S DataInput, ObjectStreams, Socket, RMI

• recommandations de programmation : répartition

• outils : JavaWorkShop (debuger), JAVASPEC,

Le Projet 1/14
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1
PHASE 5 : consolidations, extensions

principes
• compléments de réalisation : impressions, journalisation locale,
personnalisation de l’interface utilisateur.

• consolidations : analyse de code, mise en place de processus de


maintenance.

réalisation
1. Réalisations facultatives : impression d’un document attestant
d’un ordre de bourse (vente-achat d’actions), journalisation locale
des opérations effectuées par l’opérateur, personnalisations de
l’interface utilisateur, exploration de la réalisation de code natif.

2. Faire une proposition pour une sécurité/authentification


minimum dans le système.

3. Tests et analyse de code : analyse de performance, analyse de


couverture.

4. Problématique de la fabrication et de la livraison du produit fini :


faire une proposition d’organisation.

références
voir chapitres :

• rappels: JNI

• recommandatins de programmation : performances, 100% pur


java, intégration de méthodes natives,

• outils : JavaWorkShop (analyse de performances), JAVASCOPE

Le Projet 1/15
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
1

Le Projet 1/16
Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
SQL (et miniSQL) 2

1
Objectifs
• introduction à l’outil mSQL

• introduction à SQL

• manipulations sur la base existante

Références
The Practical SQL Handbook, Emerson, Darnovsky, and Bowman, Addison-
Wesley, 1989.

“mSQL Manual,” Hughes, (unpublished), 1996.

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Introduction à mSQL

Généralités
Ce cours utilise une base SQL appelée mini-SQL (mSQL).
mSQL est un produit (disponible sous licence) créé par David Hughes1.
Ce produit comprend: le moteur de base de données, une interface
"terminal" simple, un programme d’administration de la base, un
visualiseur de schema et une API en langage "C". L’API et le moteur
fonctionnent dans un environnement client/serveur en utilisant les
services de TCP/IP.

mSQL est un produit simple et performant permettant de réaliser des


requêtes SQL très simples (un sous-rensemble du SQL ANSI).

1. MiniSQL nous est fourni par Hughes Technologies Pty Ltd (Australie). Pour
plus d’informations ou pour une copie d’évaluation voir l’adresse :
www.Hughes.com.au.

SQL (et miniSQL) 2/18


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Introduction à mSQL

la réalisation de mSQL
mSQL est écrit en C et la version utilisée dans ce cours a été adaptée pour
Solaris. Au coeur de mSQL il y a le daemon msqld qui écoute sur un port
TCP/IP. Voici un extrait du manuel mSQL :

[mSQL] is a single process engine that will accept multiple


connections and serialize the queries received. It utilizes
memory mapped I/O and cache techniques to offer rapid access
to the data stored in a database. It also utilizes a stack based
mechanism that ensures that INSERT operations are performed
at the same speed regardless of the size of the table being
accessed.

The server may be accessed either via a well known TCP socket
or via a UNIX domain socket with the file system
(/dev/msqld). The availability of the TCP socket allows client
software to access data stored on machine over the network.

Les outils de mSQL


voir produit et documentation sur : http://www.Hughes.com.au

msqld – le moteur mSQL

C’est le moteur de la base de données. Le démon est lancé sur un serveur


et peut tourner avec l’identitié de root (ou avec l’identité d’un utilisateur
local). Au cours de ce stage le démon aura l’identité de root (l’animateur
désignera la machine hôte).

SQL (et miniSQL) 2/19


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Introduction à mSQL

les outils mSQL (suite)

relshow - Visualiseur de schéma mSQL

relshow permet d’interroger la base pour connaître les noms des tables
ou les caractéristiques des champs. Il peut être lancé soit localement soit à
distance :
relshow [-h hostname] database
relshow [-h hostname] database tablename

msqladmin – administration de la base (pour mémoire)

Les commandes sont:

create DataBase Crée une nouvelle base nommée: DataBase

drop DataBase Détruit la base DataBase

shutdown Demande l’arrêt du serveur mSQL

reload Demande au serveur de recharger les informations de contrôle


d’accès

version Donne diverses informations sur le produit.

Le serveur mSQL acceptera les commandes d’administration uniquement


si elles sont lancées par l’utilisateur root sur la machine serveur.Seule la
commande version peut être passée par une autre personne.

msqldump – image de la base (pour mémoire)

msqldump produit une trace qui peut être utilisée en entrée par le
terminal mSQL. On peut ainsi facilement créer des copies de la base (y
compris sur le réseau avec option -h)

SQL (et miniSQL) 2/20


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Contrôle d’accès mSQL (pour mémoire)

Le contrôle d’accès est décrit dans le fichier msql.acl dans le répertoire


d’installation de la base. Le fichier est séparé en plusieurs zone (une par
base controlée par le serveur). Sans configuration les accès sont
globalement autorisés en lecture/écriture.
Voici un exemple de zone dans ce fichier
# Sample access control for mSQL
database=test
read=bambi,paulp
write=root
host=*.Bond.edu.au,-student.it.Bond.edu.au
access=local,remote

Selon cette définition, la base test est accessible à la fois par des
connexions locales (local) et distantes (remote). Ces connexions peuvent
provenir de tout hôte dans le domain Bond.edu.au sauf pour la machine
student.it.Bond.edu.au.
L’accès en lecture est reservé uniquement à bambi et paulp (et personne
d’autre). L’accès en écriture est reservé à root.

Les contrôles sont basés sur la première correspondance trouvée. Ainsi


une ligne du type read=-*,bambi ne pourra permettre de retirer les
droits d’écriture à tout le monde sauf bambi (-* correspondra aussi à
bambi). L’entrée correcte serait plutôt read=bambi,-* bien que le -*
soit superflu parceque c’est la politique par défaut.

Attention: si dans une ligne de configuration une entrée particulière est


absente (par ex. read ), le comportement par défaut est le plus sécurisé
(du coup personne ne pourra lire!). Ceci est en contradiction avec le
comportement par défaut si la zone réservée à la base n’est pas décrite
dans le fichier de configuration: là tous les accès sont autorisés!

A noter également: les "zones" décrivant chaque base doivent être séparés
par une ligne blanche (qui marque ainsi la fin de la description de la base
courante). Il peut y avoir plusieurs lignes portant sur la même entrée
comme dans:
read=bambi,paulp
read=root

SQL (et miniSQL) 2/21


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Des caractères "jokers" (*) peuvent être utilisés dans les descriptions. Un
joker seul correspondra à toute chaîne, alors qu’un tel caractère suivi par
d’autres déclenche un "pattern matching" partiel (exemple:
*.Bond.edu.au corresond à tout ce qui peut se terminer par la chaîne
Bond.edu.au).
Une pratique saine consiste à faire, en fin de fichier, une zone avec une
entrée database=* de manière à définir des droits par défaut pour
TOUTE base.

Les informations sur les listes de contrôle d’accès peuvent être rechargées
en cours d’éxécution par msqladmin reload. Ceci réanalysera le fichier
de configuration avant de lancer la commande reload (donc uniquement
si l’analyse s’est correctment terminée). Comme pour toutes les
commandes de msqladmin cette commande ne sera acceptée que si elle
est lancée par root sur la machine serveur.

SQL (et miniSQL) 2/22


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Introduction à mSQL

les outils mSQL (suite)


msql – terminal d’interaction SQL

msql lit des requêtes en mode texte et affiche les résultats. On peut le
lancer localement ou sur un site distant:
msql [-h hostname] database

Si hostname n’est pas spécifié, msql recherche la variable d’environnement


MSQL_HOST et s’il ne la trouve pas utilise le site local.

msql reconnaît quatre commande spéciales préfixées par (\) pour les
distinguer des ordre SQL.

• \g Go, execute la requête SQL en cours (ou la requête


précédente).

• \p Print, affiche le contenu du buffer d’interrogation

• \e Edite la dernière commande dans votre éditeur par défaut.

• \q Quittter mSQL.

SQL (et miniSQL) 2/23


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Commandes mSQL

Généralités
Chaque requête SQL commence par un mot-clef particulier, mSQL répond
aux commandes suivantes :

• SELECT – Recherche d’enregistrements dans une ou plusieurs


tables..

• INSERT – ajoute un enregistrement dans une table.

• DELETE – Retire des enregistrements d’une table.

• UPDATE – Modifie des champs dans des enregistrements


particuliers.

• CREATE – Crée une nouvelle table avec les champs de noms et de


types spécifiés.

• DROP – détruit une table de la base.

Exemple : recherche de tous les champs de la table "employee_data" de


l’enregistrement pour lequel le champ "employee_id" a la valeur ’10223’
(il s’agit ici d’une chaîne de caractères et non d’un nombre):2
SELECT * FROM employee_data WHERE employee_id =
’10223’

2. Les requêtes mSQL sont indépendantes de la capitalisation des lettres, Les


exemples ci-après comportent toutefois des lettres majuscules chaque fois
qu’on utilise un mot-clef de SQL.

SQL (et miniSQL) 2/24


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Commandes mSQL

La requête SELECT
La requête SELECT est la commande élémentaire pour rechercher des
valeurs contenues dans la base. Cette commande permet les services
suivants :

• jointure entre plusieurs tables (pas de "jointure externe")

• Modifieur DISTINCT pour la sélection des enregistrements

• Clauses ORDER BY (tris)

• Recherches par expressions régulières ("joker")

• Utilisation de comparaisons entre colonnes dans les clauses


WHERE

La syntaxe générale d’une requête SELECT en mSQL (on remarquera que


ce SQL est incomplet par rapport au SQL standard):
SELECT [table.]colonne [ , [table.]colonne ]...
FROM table [ , table]...
[ WHERE [table.]colonne Operateur Valeur
[ AND | OR [table.]colonne Operateur Valeur]... ]
[ ORDER BY [table.]colonne [DESC] [, [table.]colonne
[DESC] ...]

Operateur peut être <, >, =, <=, >=, <>, ou LIKE.Valeur peut être une
colonne ou une constante littérale..

La syntaxe des expressions régulières est celle du SQL standard :

• A un caractère de soulignement (_) correspond n’importe quel


caractère (et un seul). A un caractère pourcent (%) correspond 0,1
ou plusieurs caractères.

• Un anti-slash (\) est un caractère d’échappement pour les


caractères spéicaux (par exemple, \% doit correspondre un % et \\
correspond à un \).

• tous les autres caractères correspondent à eux-mêmes.

SQL (et miniSQL) 2/25


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
commandes mSQL

La requête SELECT (suite)

Exemples

SELECT first_name, last_name FROM emp_details


WHERE dept = 'finance'

Pour trier les résultats dans l’ordre ascendant pour le nom (last_name) et
en ordre descendant pour le prénom (first_name) :
SELECT first_name, last_name FROM emp_details
WHERE dept = 'finance'
ORDER BY last_name, first_name DESC

Lorsque des résultats comprennent les mêmes combinaisons de valeurs le


modifieur DISTINCT permet d’éliminer les "doublons" :
SELECT DISTINCT last_name FROM emp_details
WHERE dept = 'finance'
ORDER BY last_name

Pour rechercher toute personne dans le département "finance" dont le


nom ressemble à "Dupon" (tels que "Dupond" et "Dupont")
SELECT first_name, last_name FROM emp_details
WHERE dept = 'finance' AND last_name LIKE 'Dupon_'

SQL (et miniSQL) 2/26


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Commandes mSQL

La requête SELECT (suite)

Jointures

C’est l’opération qui permet d’opérer des recherches en établissant des


relations entre deux ou plusieurs tables.

Exemple : une table décrit les employés (emp_details) et une autre table
decrit les équipes de projet (project_detail). Chaque membre d’une équipe
est repéré par un code (emp_id) qui identifie de manière unique un
employé. Pour avoir les informations détaillées sur qui travaille dans quel
projet :
SELECT emp_details.first_name, emp_details.last_name,
project_details.project
FROM emp_details, project_details
WHERE emp_details.emp_id = project_details.emp_id
ORDER BY emp_details.last_name, emp_details.first_name

La jointure entre les deux tables se fait par leurs champs emp_id respectifs
(on notera que ce champ est une clef dans la table emp_details).

mSQL ne limite pas le nombre de tables que l’on peut impliquer dans une
jointure.


en mSQL tous les noms de colonnes dans une jointure doivent être
qualifiés (c’est à dire rattachés à une table). Il n’y a pas de rattachement
implicite d’une colonne à une table.

SQL (et miniSQL) 2/27


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Commandes mSQL

La commande INSERT
La commande INSERT permet d’ajouter de nouveaux enregistrements à
une table. Il faut spécifier à la fois les noms des champs (décrire le N-
uplet) et la combinaison de valeurs correspondantes (le N-uplet lui-
même) .
INSERT INTO table_name ( column [ , column ]... )
VALUES (value [, value]... )

exemple:
INSERT INTO emp_details ( first_name, last_name, dept,
salary)
VALUES ('David', 'Hughes', 'I.T.S.','12345')

Contrairement au SQL standard on ne peut mettre une requête SELECT à


l’intérieur d’une requête INSERT..

La commande DELETE
La commande DELETE permet de détruire des enregistrements d’une
table. La syntaxe en est:
DELETE FROM table_name
WHERE column Operateur Valeur
[ AND | OR column Operateur Valeur ]...

Operateur peut être <, >, =, <=, >=, <>, ou LIKE

Exemple:
DELETE FROM emp_details WHERE emp_id = ’12345’

SQL (et miniSQL) 2/28


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Commandes mSQL

La commande UPDATE
La commande UPDATE permet de changer une ou plusieurs valeurs de
champs dans un enregistrement existant. En mSQL seules des valeurs
littérales peuvent être utilisées pour spécifier la nouvelle valeur d’un
champ (on ne peut pas indiquer un nom de colonne par ex.)
UPDATE table_name SET column=Valeur [, column=Valeur ]...
WHERE column Operateur Valeur
[ AND | OR column Operateur Valeur ]...

Operateur peut être <, >, =, <=, >=, <>, ou LIKE.

Exemple:
UPDATE emp_details SET salary=30000 WHERE emp_id = ’1234’

SQL (et miniSQL) 2/29


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Commandes mSQL

La commande CREATE (pour mémoire)


En mSQL la commande CREATE peut seulement être utilisée pour créer
une table (on ne peut pas réaliser d’autres définitions comme une vue).
ATTENTION : il ne peut y avoir qu’une seule clef primaire par table. La
définition d’un champ comme étant un clef entraîne automatiquement la
propriété "not null" .
CREATE TABLE table_name (
col_name col_type [ not null | primary key ]
[ , col_name col_type[ not null | primary key ]] ...
)

Exemple:
CREATE TABLE emp_details(
first_name char(15) not null,
last_name char(15) not null,
dept char(20),
emp_id int primary key,
salary int
)

Les types disponibles sont:

• char (len)

• int

• real

La commande DROP (pour mémoire)


Drop permet de détruire une table dans la base:
DROP TABLE table_name

Exemple :

DROP TABLE emp_details

SQL (et miniSQL) 2/30


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Exercices

1. Lancer msql sur la base StockMarket . L’animateur doit fournir le


nom de la machine serveur. Afficher toutes les informations
présentes dans les trois tables. Exemple:
% msql -h serveur StockMarket

Welcome to the miniSQL monitor. Type \h for help.

mSQL > select * from Stock


> \g

Query OK.

10 rows matched.

+-----------------+--------------+
| symbol | price |
+-----------------+--------------+
| SUNW | 68.75 |
| CyAs | 22.625 |
| DUKE | 6.25 |
| ABStk | 18.5 |
| JSVCo | 9.125 |
| TMAs | 82.375 |
| BWInc | 11.375 |
| GMEnt | 44.625 |
| PMLtd | 203.375 |
| JDK | 33.5 |
+-----------------+--------------+

mSQL >

SQL (et miniSQL) 2/31


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
2
Exercices

2. Créer et exécuter les requêtes suivantes:


ATTENTION: ne créer ni détruire aucune table..

a. Afficher toutes les valeurs dont la cote est supérieure à 50.

b. Ajouter dans la base un enregistrement vous décrivant vous-


même..

c. Afficher tous les clients en les triant par ordre alphabétique.

d. Ajouter deux enregistrements dans votre portefeuille et


vérifier si la base a bien tenu compte de votre ordre.

e. Vendez toutes les parts sur une valeur de votre portefeuille et


la moitié des parts sur une autre valeur.

f. Détruisez-vous en tant que client et mettez à jour la table des


portefeuilles.

SQL (et miniSQL) 2/32


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
rappels: API JDBC 3

Plan du cours
L’API Java de connectivité des bases de données (JDBC) permet aux
développeurs d’écrire un code d’accès à une base de données, sans
connaître la réalisation concrète de cette base.

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Introduction

L´API JDBC contient une série d’interfaces conçues pour permettre au


développeur d’applications qui travaillent sur des bases de données de le
faire indépendamment du type de base utilisé. La connectivité JDBC
permet au développeur de se concentrer sur l’écriture de l’application en
s’assurant que les interrogations de la base de données sont correctes et
que les données sont manipulées conformément à leur conception.

La connectivité JDBC permet au développeur d’écrire une application en


utilisant les noms d’interfaces et les méthodes décrites dans l’API, sans
tenir compte de leur réalisation dans le pilote (driver JDBC). Le
développeur utilise les interfaces décrites dans l’API comme s’il s’agissait
de classes courantes. Le constructeur du pilote fournit une réalisation de
classe pour chaque interface de l’API. Lorsqu’une méthode d’interface est
utilisée, elle se réfère en fait à une instance d’objet d’une classe ayant
réalisé cette interface.

Bibliographie
• Caractéristiques JDBC : http://java.sun.com/products/jdbc

• The Practical SQL Handbook par Emerson, Darnovsky et Bowman


(Editions Addison-Wesley, 1989)

rappels: API JDBC 3/34


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
“Pilote” JDBC

Chaque pilote de base de données doit fournir une classe réalisant


l’interface java.sql.Driver. Cette classe est alors utilisée par la classe
générique java.sql.DriverManager lorsqu’un pilote est requis pour
assurer la connexion à une base de données spécifique. Cette connexion
s’opère à l’aide d’une URL (identificateur de ressources).

Vous utiliserez COM.imaginary.sql.msql.MsqlDriver1, un pilote JDBC


écrit pour une connexion à une base de données Mini-SQL2. Le pilote
Imaginary illustre la flexibilité du langage Java.

1. API mSQL-JDBC fournie avec l’aimable autorisation de George


Reese.http://www.imaginary.com/~borg
2. Mini SQL fourni avec l’aimable autorisation de Hughes Technologies Pty Ltd,
Australie.

rappels: API JDBC 3/35


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Pilotes JDBC

Application Java
(API JDBC)

Gestionnaire de pilotes JDBC

URL URL
URL URL

Pilote Pilote de liaison


Pilote A Pilote B
JDBC-NET JDBC-ODBC

Pilotes ODBC
et de bases Possibilités d’implémentation JDBC
de données

rappels: API JDBC 3/36


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Organigramme JDBC

L’enchainement des appels


Du point de vue du programmeur JDBC les tâches s’enchainent de la
manière suivante :

• Création d’une instance d’un driver JDBC.

• détermination de la base

• Ouverture d’une connexion à la base

• Allocation d’un contexte de requête (Statement)

• Soumission d’une requête

• Récupération des résultats

Package java.sql
Huit interfaces sont associées à l’API JDBC :

• Driver

• Connection

• Statement

• PreparedStatement

• CallableStatement

• ResultSet

• ResultSetMetaData

• DatabaseMetaData

rappels: API JDBC 3/37


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Organigramme JDBC

Chacune de ces interfaces permet à un programmeur d’application


d’établir des connexions à des bases de données spécifiques, d’exécuter
des instructions SQL et de traiter les résultats.

DriverManager

Driver Driver

Connection Connection

Connection Statement

ResultSet

Statement Statement Statement

ResultSet ResultSet

Figure 1-1 Organigramme JDBC

• Une chaîne d’URL est transmise à la méthode getConnection()


du gestionnaire de pilotes (DriverManager) qui localise à son
tour un pilote (Driver).

• Un pilote vous permet d’obtenir une connexion (Connection).

• Cette connexion vous permet de créer une requête (Statement).

• Lorsqu’une requête est exécutée avec une méthode


executeQuery(), un résultat (ResultSet) peut être retourné.
✓ Un objet ResultSet est toujours retourné mais il ne contient pas nécessairement de
données, c’est-à-dire lorsqu’une mise à jour ou une requête d’insertion est exécutée.

rappels: API JDBC 3/38


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Exemple JDBC

Cet exemple simple utilise la base de données Mini-SQL, ainsi que les
éléments d’une application JDBC. Les opérations réalisées seront les
suivantes : création d’une instance Driver, obtention d’un objet
Connection, création d’un objet Statement et exécution d’une requête,
puis traitement de l’objet retourné ResultSet.
1 import java.sql.*;
2 import COM.imaginary.sql.msql.*;
3
4 public class JDBCExample {
5
6 public static void main (String args[]) {
7
8 if (args.length < 1) {
9 System.err.println ("Usage:");
10 System.err.println (" java JDBCExample <db server hostname>");
11 System.exit (1);
12 }
13 String serverName = args[0];
14 try {
15 // Create the instance of the Msql Driver
16 new MsqlDriver ();
17
18 // Create the "url"
19 String url = "jdbc:msql://" + serverName +
20 ":1112/StockMarket";
21
22 // Use the DriverManager to get a Connection
23 Connection mSQLcon = DriverManager.getConnection (url);
24
25 // Use the Connection to create a Statement object
26 Statement stmt = mSQLcon.createStatement ();
27
28 // Execute a query using the Statement and return a ResultSet
29 ResultSet rs = stmt.executeQuery
30 "SELECT ssn, cust_name FROM Customer" +
31 " order by cust_name");

rappels: API JDBC 3/39


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Exemple JDBC

32 // Print the results, row by row


33 while (rs.next()) {
34 System.out.println ("");
35 System.out.println ("Customer: " + rs.getString (2));
36 System.out.println ("Id: " + rs.getString (1));
37 }
38
39 } catch (SQLException e) {
40 e.printStackTrace();
41 }
42 }
43 }

Résultats:
% java JDBCExample serveur

Customer: Tom McGinn


Id: 999-11-2222

Customer: Jennifer Sullivan Volpe


Id: 999-22-3333

Customer: Georgianna DG Meagher


Id: 999-33-4444

Customer: Priscilla Malcolm


Id: 999-44-5555

rappels: API JDBC 3/40


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Création de pilotes JDBC

Il existe deux méthodes pour créer une instance de pilote JDBC :


explicitement ou à l’aide de la propriété jdbc.drivers.

Création explicite d’une instance de pilote JDBC


Pour communiquer avec un moteur de base de données particulier en
JDBC, vous devez préalablement créer une instance pour le pilote JDBC.
Ce pilote reste en arrière plan et traite toutes les requêtes pour ce type de
base de données.
// Create an instance of Msql’s JDBC Driver
new MsqlDriver();

Il n’est pas nécessaire d’associer ce pilote à une variable car le pilote est
référencé par un objet statique.

rappels: API JDBC 3/41


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Création de pilotes JDBC

Chargement des pilotes JDBC via jdbc.drivers


Il est tout à fait possible que plusieurs pilotes de bases de données soient
chargés en mémoire. Il peut également arriver que plusieurs de ces
pilotes, ODBC ou protocoles génériques de réseau JDBC, soient en mesure
de se connecter à la même base de données. Dans ce cas, l’interface JDBC
permet aux utilisateurs de définir une liste de pilotes dans un ordre
spécifique. Cet ordre de sélection est défini par un paramètre de
propriétés Java, jdbc.drivers. La propriété jdbc.drivers doit être
définie sous forme de liste de noms de classes de pilotes, séparés par le
symbole deux points (“:”) :
jdbc.drivers=COM.imaginary.sql.msql.MsqlDriver:Acme.wonder.driver

Les propriétés sont définies par l’option -D de l’interpréteur java (ou


l’option -J de l’application appletviewer). Exemple :
% java -Djdbc.drivers=COM.imaginary.sql.msql.MsqlDriver:\
Acme.wonder.driver

Lors d’une tentative de connexion à une base de données, l’API JDBC


utilise le premier pilote trouvé susceptible d’établir la connexion à l’URL
défini. L’API essaie tout d’abord chaque pilote défini dans cette
propriétés, dans l’ordre de gauche à droite. Elle essaie ensuite tous les
pilotes déjà chargés en mémoire en respectant l’ordre de chargement. Si le
pilote a été chargé par un code non sécurisé, il est alors ignoré sauf s’il a
été chargé à partir de la même source que le code tentant d’établir la
connexion.

rappels: API JDBC 3/42


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Pilotes JDBC

Désignation d’une base de données


Après avoir créé l’instance du pilote JDBC, vous devez à présent indiquer
la base de données à laquelle vous souhaitez vous connecter.

Dans JDBC, il vous suffit de spécifier un URL indiquant le type de base de


données. La syntaxe des chaînes d’URL proposée pour une base de
données JDBC est :
jdbc:sous_protocole:parametres

sous_protocole désigne un type spécifique de mécanisme de


connectivité des bases de données, pouvant être supporté par un ou
plusieurs pilotes. Le contenu et la syntaxe de parametres dépendent du
sous-protocole.
// Construct the URL for JDBC access
String url = new String ("jdbc:msql://" + servername
+ ":1112/StockMarket");

Cet URL vous permettra d’accéder à la base de données mSQL


StockMarket à laquelle vous vous connecterez lors des exercices.
serverName est une variable définissant le nom d’hôte du serveur de la
base de données.

rappels: API JDBC 3/43


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Connexion JDBC

Connexion à une base de données


Après avoir créé un URL définissant msql en tant que moteur de base de
données, vous pouvez à présent établir une connexion à la base de
données.

A cet effet, on doit obtenir un objet java.sql.Connection en appelant la


méthode java.sql.DriverManager.getConnection du pilote JDBC.
// Establish a database connection through the msql
// DriverManager
Connection mSQLcon =
DriverManager.getConnection(url);

Le processus est le suivant :

• Le gestionnaire de pilotes (DriverManager) appelle la méthode


Driver.getConnection pour chaque pilote enregistré, en
transmettant la chaîne d’URL sous forme de paramètre.

• Si le pilote identifie le nom du sous-protocole, il retourne alors une


instance d’objet Connection ou une valeur nulle le cas échéant.

rappels: API JDBC 3/44


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Pilotes JDBC

Interrogation d’une base de données


La figure 2-4 décrit la méthode permettant à un gestionnaire de pilotes
(DriverManager) de traduire une chaîne URL transmise dans la méthode
getConnection(). Lorsque le pilote retourne une valeur nulle, le
gestionnaire appelle le pilote enregistré suivant jusqu’à la fin de la liste ou
jusqu’à ce qu’un objet Connection soit retourné.

Chaîne URL
Gestionnaire de pilotes Programme

getConnection (chaîne URL);

Pilote Pilote Pilote


jdbc:A jdbc:B jdbc:msql

Explication Connexion à la
base de données
Le gestionnaire de pilotes appelle StockMarket
getConnection(URL) qui appelle
driver.connection(URL) pour les pilotes du
vecteur jusqu’à ce qu’une correspondance soit trouvée.
L’URL est analysé (jdbc:drivername).
Lorsque le pilote du vecteur correspond au drivername analysé, une
connexion est établie.
Si le pilote ne correspond pas, la valeur NULL est retournée et le StockMarket
pilote suivant du vecteur est examiné.

rappels: API JDBC 3/45


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Instructions JDBC

Soumission d’une requête


Pour soumettre une requête standard, créez tout d’abord un objet
Statement à partir de la méthode Connection.createStatement.
// Create a Statement object
try {
stmt = mSQLcon.createStatement();
} catch (SQLException e) {
System.out.println (e.getMessage());
}

Utilisez la méthode Statement.executeUpdate() pour soumettre un


INSERT,un UPDATE ou un DELETE .
// Pass a query via the Statement object
int count = stmt.executeUpdate("DELETE from
Customer WHERE ssn=’999-55-6666’");

La méthode Statement.executeUpdate() renvoie un entier qui


représente le nombre d’enregistrements affectés.

Utilisez la méthode Statement.executeQuery() pour soumettre


l’instruction SQL à la base de données. Notez que JDBC transmet
l’instruction SQL à la connexion de base de données sous-jacente sans
modification. JDBC ne tente aucune interprétation des requêtes.
// Pass a query via the Statement object
ResultSet rs = stmt.executeQuery("SELECT DISTINCT *
from Customer order by ssn");

La méthode Statement.executeQuery() renvoie un résultat de type


ResultSet pour traitement ultérieur.

rappels: API JDBC 3/46


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Instructions JDBC

requête préparée (non disponible sous mSQL)


En cas d’exécution répétitive des mêmes instructions SQL, l’utilisation
d’un objet PreparedStatement s’avère intéressante. Une requête préparée
est une instruction SQL précompilée qui est plus efficace qu’une
répétition d’appels de la même instruction SQL. La classe
PreparedStatement hérite de la classe Statement pour permettre le
paramétrage des instructions JDBC. Le code suivant présente un exemple
d’utilisation d’une instruction préformattée :

Exemple
public boolean prepStatement(Reservation obj){
PreparedStatement prepStmnt =
msqlConn.prepareStatement( "UPDATE Flights SET
numAvailFCSeats = ? WHERE flightNumber = ?" );
prepStmnt.setInt(1,
(Integer.parseInt(obj.numAvailFCSeats) - 1));
prepStmnt.setLong(2, obj.FlightNo);
int rowsUpdated = prepStmnt.executeUpdate();
return (rowsUpdated > 0) ;
}

Les méthodes setXXX


Les méthodes setXXX de configuration des paramètres SQL IN doivent
indiquer les types compatibles avec le type SQL de paramètre d’entrée
défini. Ainsi, si un paramètre IN est du type SQL Integer, setInt doit
être utilisé.

rappels: API JDBC 3/47


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Méthodes setXXX

Table 1: Méthodes setXXX et types SQL

Méthode Type(s) SQL

setASCIIStream Utilise une chaîne ASCII pour générer un


LONGVARCHAR
setBigDecimal NUMERIC
setBinaryStream LONGVARBINARY
setBoolean BIT
setByte TINYINT
setBytes VARBINARY ou LONGVARBINARY (selon la taille
par rapport aux limites de VARBINARY)
setDate DATE
setDouble DOUBLE
setFloat FLOAT
setInt INTEGER
setLong BIGINT
setNull NULL
setObject L’objet Java défini est converti en type SQL
cible avant d’être envoyé
setShort SMALLINT
setString VARCHAR ou LONGVARCHAR (selon la taille par
rapport aux limites du pilote sur VARCHAR)
setTime TIME
setTimestamp TIMESTAMP
setUnicodeStream UNICODE

rappels: API JDBC 3/48


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Instructions JDBC

procédure stockée (non disponible sous mSQL)


Une procédure stockée permet l’exécution d’instructions non SQL dans la
base de données. La classe CallableStatement hérite de la classe
PreparedStatement qui fournit les méthodes de configuration des
paramètres IN. Etant donné que la classe PreparedStatement h érite de
la classe Statement, la méthode de récupération de résultats multiples
par une procédure enregistrée est supportée par la méthode
Statement.getMoreResults.

Ainsi, vous pourriez utiliser une instruction CallableStatement pour


enregistrer une instruction SQL précompilée, vous permettant
d’interroger une base de données contenant les informations sur la
disponibilité des sièges pour un vol particulier.

rappels: API JDBC 3/49


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Instructions JDBC

Exemple
String planeID = "727";
CallableStatement querySeats =
msqlConn.prepareCall("{call
return_seats(?, ?, ?, ?)}");
try {
querySeats.setString(1, planeID);
querySeats.registerOutParameter(2,
java.sql.Type.INTEGER);
querySeats.registerOutParameter(3,
java.sql.Type.INTEGER);
querySeats.registerOutParameter(4,
java.sql.Type.INTEGER);
querySeats.execute();
int FCSeats = querySeats.getInt(2);
int BCSeats = querySeats.getInt(3);
int CCSeats = querySeats.getInt(4);
} catch (SQLException SQLEx){
System.out.println("Query failed");
SQLEx.printStackTrace();
}

Appel de procédure
Avant d’exécuter un appel de procédure stockée, vous devez
explicitement appeler registerOutParameter pour enregistrer le type
java.sql.Type de tous les paramètres SQL OUT.

rappels: API JDBC 3/50


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Instructions JDBC

Récupération de résultats
Le résultat de l’exécution d’une instruction peut se présenter sous forme
de table de données accessible via un objet java.sql.ResultSet. Cette
table se compose d’une série de lignes et de colonnes. Les lignes sont
récupérées dans l’ordre. Un objet ResultSet maintient un curseur sur la
ligne de données courante et le positionne tout d’abord sur la première
ligne. Le premier appel de l’instruction next définit la première ligne en
tant que ligne courante, le second appel déplace le curseur sur la seconde
ligne, etc.

L’objet ResultSet fournit une série de méthodes get permettant


d’accéder aux nombreuses valeurs de colonne de la ligne courante. Ces
valeurs peuvent être récupérées à partir du nom de la colonne ou d’un
indice. Il est généralement plus pratique d’utiliser un indice pour
référencer une colonne. Les indices de colonne débutent à 1.

rappels: API JDBC 3/51


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Instructions JDBC

Réception de résultats (suite)


while (rs.next()) {
System.out.println ("Customer: " + rs.getString(2));
System.out.println ("Id: " + rs.getString(1));
System.out.println ("");
}

Les diverses méthodes getXXX accèdent aux colonnes dans la table de


résultats. Il est possible d’accéder aux colonnes d´une ligne dans
n’importe quel ordre.

Nota: il est possible de découvir dynamiquement des informations sur la


table comme le nombre de champs dans un enregistrement, le type de
chaque champ, etc. Ce type d’information est géré par l’objet
ResultSetMetaData rendu par getMetaData() -service non accessible
en mSQL-

Pour récupérer des données extraites de l’objet ResultSet, vous devez


vous familiariser avec les colonnes retournées, ainsi qu’avec les types de
données qu’elles contiennent. La table 2-3 établit une correspondance
entre les types de données Java et SQL.

rappels: API JDBC 3/52


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Méthodes getXXX

Table 2: Méthodes getXXX et type de données Java retourné

Méthode Type de données Java retourné

getASCIIStream java.io.InputStream
getBigDecimal java.math.BigDecimal
getBinaryStream java.io.InputStream
getBoolean boolean
getByte byte
getBytes byte[]
getDate java.sql.Date
getDouble double
getFloat float
getInt int
getLong long
getObject Object
getShort short
getString java.lang.String
getTime java.sql.Time
getTimestamp java.sql.Timestamp
getUnicodeStream java.io.InputStream de caractères Unicode

rappels: API JDBC 3/53


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Correspondance des types de données SQL en Java

La table 2-3 présente les types Java standard pour la correspondance avec
divers types SQL courants.

Table 3: Correspondance de types SQL en Java

Type SQL Type Java

CHAR String
VARCHAR String
LONGVARCHAR String (ou Stream)
NUMERIC java.math.BigDecimal
DECIMAL java.math.BigDecimal
BIT boolean
TINYINT byte
SMALLINT short
INTEGER int
BIGINT long
REAL float
FLOAT double
DOUBLE double
BINARY byte[]
VARBINARY byte[]
LONGVARBINARY byte[]
DATE java.sql.Date
TIME java.sql.Time
TIMESTAMP java.sql.Timestamp

rappels: API JDBC 3/54


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Utilisation de l’API JDBC

En créant une série générique d’interfaces permettant d’établir une


connexion à tout produit de base de données grâce à l’API JDBC, vous
n’êtes limité ni à une base de données spécifique, ni à une architecture
particulière d’accès car plusieurs solutions peuvent être envisagées.

Types de conception des pilotes JDBC


La conception de l’architecture des accès base de données que vous
choisissez d’implanter dépend en partie du pilote JDBC.

• Conception en deux éléments – Utilisant le langage Java vers des


bibliothèques de méthodes natives ou Java vers un protocole de
système de gestion de base de données (SGBD) natif (tous les
codes en Java mais protocole spécifique)

• Conception en trois éléments – Utilisant tous les codes Java dans


lesquels les appels JDBC sont convertis en protocole indépendant
du système SGBD.

• Conception en deux ou trois éléments – Spécialement conçue


pour fonctionner avec les pilotes de bases de données ODBC
(connectivité ouverte aux bases de données Microsoft), dans
lesquels les appels JDBC sont effectués par le biais d’un pilote
ODBC (généralement une librairie spécifique à la plate-forme)

A ce jour, les principaux développements de pilotes de bases de données


ont été réalisés par des constructeurs indépendants, non associés à une
société de fourniture de bases de données. Cette situation est avantageuse
pour le développeur car elle implique que les solutions ne sont
généralement pas privées et que la concurrence régule les prix.

rappels: API JDBC 3/55


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Types d’architecture d’accès aux bases de données

Conceptions en deux niveaux


Une conception en deux niveaux permet à l’utilisateur de dialoguer avec
une application frontale (client) directement connectée à la base de
données (serveur).

Une application de base de données conçue en deux niveaux peut utiliser


l’un des deux types de pilotes JDBC suivants :

• Pilote s´appuyant sur une API native – Utilise une librairie


(généralement C ou C++) compilée et développée pour
l’équipement spécifique et le système d’exploitation sur lequel
s´exécute l’application cliente. Ce type de pilote limite donc le
programme client à une application Java ou une applet (local sur
le disque dur de l’utilisateur) puisque le pilote doit effectuer des
appels de méthodes natives (ou lire des classes présentes sur le
poste client).

• Pilote de protocole natif – Utilise le protocole (en général privé)


spécifique, fourni par le constructeur de la base de données. Cela
signifie que le serveur du constructeur de base de données
contient une application de réception TCP/IP acceptant les
connexions de plusieurs applications clients. Le client utilise un
protocole spécifié par le constructeur de base de données pour
communiquer les requêtes et retourner les résultats.

rappels: API JDBC 3/56


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Types d’architecture d’accès aux bases de données

Conceptions en trois niveaux


Les conceptions intègrent un processus intermédiaire entre l’application
finale et le serveur de base de données. Bien que cette conception semble
augmenter le temps système, elle présente néanmoins plusieurs
avantages:

• La validation des données est transférée au middleware (le niveau


intermédiaire).

• Le client peut accéder à plusieurs bases de données par le biais


d’une seule connexion par socket. Il devient donc possible d’écrire
l’application client sous forme d’applet, téléchargé à partir d’un
browser.

• Le protocole client/middleware est défini par le constructeur et


dépend du SGBD. L’opération de connexion à la base de données
est donc transférée du client au middleware.

• Le middleware peut inclure des fonctions non offertes par une ou


plusieurs bases de données, telles que le verrouillage
d’enregistrements ou la notification de modification
d’enregistrement.

Les applications d’accès aux bases de données conçues en deux ou trois


niveaux peuvent utiliser un pilote entièrement rédigé en Java. Dans ce
cas, le pilote JDBC traduit les appels en protocole middleware. Le
middleware est alors chargé de sélectionner la base de données adéquate.

rappels: API JDBC 3/57


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Applets

L’applet Java a constitué l’utilisation la plus médiatique de la plate-forme


Java. L’interface JDBC peut être intégrée dans des applets pour rendre la
base de données accessible au World Wide Web (WWW). Ainsi, un
utilisateur peut télécharger un applet Java capable d’afficher les vols
disponibles à une date définie, en partance et à l’arrivée de destinations
spécifiées. Cet applet pourrait accéder à une base de données relationnelle
via Internet, pour permettre à un client de se renseigner sur les places non
réservées, d’effectuer une réservation ou une mise à jour de la base.

Les applets peuvent également être utilisées dans un scénario intranet


pour fournir l’accès aux bases de données de la compagnie, telles qu’un
répertoire d’entreprise, dans lesquelles plusieurs services travaillent sur
différentes plates-formes matérielles, mais requièrent une interface de
base de données commune.

Applets et applications de bases de données traditionnelles


Il existe plusieurs différences entre les applets et les applications de bases
de données traditionnelles :

• Les applets non sécurisées sont soumises à de sévères contraintes


dans les opérations qu´elles désirent effectuer. Dans la majorité des
cas, il est interdit aux Applets non sécurisées d’accéder aux fichiers
locaux et il leur est impossible d’établir une connexion de réseau
sur une station différente de celle ayant fourni l’applet.

• Les applets présentes sur Internet ne peuvent pas connaitre


l´emplacement de base de données locale ou du pilote de base se
trouvant dans un fichier local de la machine client, comme dans
ODBC.

Performances
Les performances relatives aux implémentations de connectivité diffèrent
selon que la base de données se trouve ou non sur le réseau. Le temps de
réponse d’une applet de base de données Internet sera très supérieur à
celui d’une applet de réseau local.

rappels: API JDBC 3/58


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Applets

Contraintes de sécurité
Certaines contraintes de sécurité rencontrés avec des applets non
sécurisés peuvent apparaître lors de l’utilisation d’une signature digitale
ou d’un scénario à clé cryptographique. Dans ce cas, une applet est traitée
comme une application au sens sécuritaire, mais il subsistera toujours des
problèmes entre les bases de données du client en raison de la difficulté à
localiser la structure de répertoire de la base de données ou du pilote de
base de données.

Comme nous l’avons vu précédemment une conception d’accès à la base


de données en trois niveaux peut fournir un middleware de service sur le
réseau. La mise en place de middleware permet d’accéder aux bases de
données sur plusieurs hôtes reliés en réseau. Ces appels pourraient être
effectués par le biais d’invocations de procédures à distance (RPC) ou
d’un navigateur de requête d’objet (ORB). Dans chaque cas, un paradigme
d’objet permet de définir au mieux le middleware (exemple : “objets
client” avec opérations pour la facturation des clients, les réservations et
autres transactions).

rappels: API JDBC 3/59


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
3
Evolutions

La programmation JDBC reste une programmation, parfois fastidieuse, de


relativement bas niveau.

La pratique de l’accès Java aux bases de données s’orientera à l’avenir


vers des APIs de plus haut niveau permettant de gérer automatiquement
les couches “basses” de l’accès aux bases de données à partir de la
définition de classes JAVA.

JAVA BLEND est un tel ensemble d’outils et d’API qui s’appuie du JDBC
et sur JTS (Java Transaction Service : API d’accès aux services
transactionnels).

rappels: API JDBC 3/60


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
Rappels : AWT 4

Objectifs
Rappels sur :

• Les interactions graphiques: composants, méthodes graphiques

• Les LayoutManagers

• La gestion des événements

• Les composants les plus courants

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Accès au manipulations graphiques

Le package AWT
Le package AWT fournit les objets pour accéder aux services du terminal
virtuel portable.

Une notion fondamentale dans ce package est la hiérarchie Component


(un objet graphique) et Container (dérivé du précédent: on peut
disposer plusieurs Components DANS un Container)

Exemples de Container : Frame (une fenêtre), Panel (un "panneau") et


son dérivé particulier qu’est l’Applet.

Exemples de Component: Button, Label (un étiquette), TextField


(une zone de saisie Texte), Canvas (zone de dessin graphique).

On peut faire des opérations graphiques sur certains composants en


agissant sur le comportement des méthodes de rafraîchissement d’image:

• repaint() -demande asynchrone de remise à jour de l’image


d’affichage-,

• update(Graphics gr) -effacement du contexte graphique


(Graphics) et appel des opérations de dessin-,

• paint(Graphics gr) -réalisation effective du dessin-

Les primitives graphiques de dessin sont liées à la classe Graphics

Les primitives graphiques peuvent être utilisées pour "décorer" des


composants d’un type prédéfini ou même pour créer des "Composants
poids-plume" en agissant sur des objets créés en sous-classant directement
Component ou Container.De tels objets graphiques sont initialement
transparents et ne sont pas associés à des objets natifs du système de
fenêtrage local, il faut gérer par programme l’ensemble de leur
comportement (aspects , événements).
De tels objets constituent l’essentiel de bibliothèques d’objets d’interaction
comme les JFC (JAVA Foundation Classes)

Rappels : AWT 4/62


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Les gestionnaires de Disposition (LayoutManager)

Un des points forts de JAVA est de permettre de faire exécuter le même


programme sur des plateformes différentes sans en modifier le code. Pour
les interactions graphiques une des conséquences de cette situation est
qu’un même programme va devoir s’afficher sur des écrans ayant des
caractéristiques très différentes. On ne peut donc raisonnablement
s’appuyer sur un positionnement des composants en absolu (avec des
coordonnées X et Y fixes).

La disposition relative des différents composants à l’intérieur d’un


Container sera prise en charge par un "gestionnaire de disposition"
attaché à ce container. Ce LayoutManager va savoir gérer les positions
des composants en fonctions des déformations subies par le Container
correspondant.

A chaque Container est associé une liste des composants contenus.


Attention une instance de composant ne peut être disposée qu’à UN
SEUL endroit (il ne sert à rien de faire plusieurs opérations add() avec le
même composant -sauf si on veut explicitement le faire changer de zone
d’affichage-)

Quelques gestionnaires standard :

1. FlowLayout : dispose les composants "en ligne". C’est le


gestionnaire par défaut des Panels.
panneau.add(new Button("bouton 1")) ;
panneau.add(new Button("bouton 2")) ;

2. BorderLayout : dispose des zones dans des points cardinaux


autour d’une zone centrale qui tend à occuper la plus large place
possible. C’est le gestionnaire par défaut des Frames.
Panel panCentral = new Panel() ;
Panel panBas = new Panel() ;

fenêtre.add(panCentral, BorderLayout.CENTER);
fenêtre.add(panBas, BorderLayout.SOUTH);

panBas.add(new Button("OK")); // ici Flowlayout

Rappels : AWT 4/63


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
3. CardLayout : permet de disposer des composants dans une "pile"
seul le composant du dessus est visible et on dispose de méthodes
spéciales pour faire passer un composant particulier sur le
"dessus" de la pile.

4. GridBagLayout : dispose les composants à l’intérieur des


"cellules" d’une table. Chaque ligne ou colonne de la table peut
avoir des dimensions différentes de celles des autres lignes ou
colonnes (quadrillage irrégulier).
Les paramètres controlant la mise en place d’un composant
particulier sont décrits par une instance de la classe
GridBagConstraints (on peut utiliser sans risque la même
instance pour plusieurs composants)
Component[][] tbComp = {.{...}, {...},...} ;
this.setLayout(new GridBagLayout()) ;
GridBagConstraints parms = new GridBagConstraints();
parms.anchor=GridBagConstraints.WEST;
parms.weightx=parms.weighty=1.0 ;
for( iy= 0; iy <tbComp.length; iy++) {
parms.gridy= iy ;
for (ix= 0; ix < tbComp[iy].length; ix++){
parms.gridx= ix ;
this.add(tbcomp[iy][ix], parms);
}
}

a. gridx, gridy : donne les coordonnées x, y de l’objet dans la grille


(celle-ci déduit automatiquement son propre nombre de lignes
et de colonnes)

b. gridwidth, gridheight : nombre de cellules occupées par le


composant

c. fill : direction du remplissage (le composant tend alors à


occuper toute sa cellule dans la direction donnée). Valeurs:
NONE, BOTH, VERTICAL, HORIZONTAL

d. anchor: lorsqu’un composant est plus petit que sa cellule, bord


d’ancrage du composant (un point cardinal: EAST,
NORTHEAST, etc..)

e. insets: détermination des "goutières" (distance minimum entre


le composant et les frontières de sa cellule)

f. weightx,weighty : "poids" relatif de la cellule (valeur entre 0 et 1)

Rappels : AWT 4/64


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Les événements

Lorsque l’utilisateur effectue une action au niveau de l’interface


utilisateur, un événement est émis. Les événements sont des objets qui
décrivent ce qui s’est produit. Il existe différents types de classes
d’événements pour décrire des catégories différentes d’actions utilisateur.

Evénements sources
Un événement source (au niveau de l’interface utilisateur) est le résultat
d’une action utilisateur sur un composant AWT. A titre d’exemple, un clic
de la souris sur un composant bouton génère (source) un ActionEvent.
L’ActionEvent est un objet (une instance de la classe) contenant des
informations sur le statut de l’événement :

● ActionCommand : nom de commande associé à l’action.

● modifiers : tous modificateurs mobilisés au cours de l’action.

Traitements d’événements
Lorsqu’un événement se produit, ce dernier est reçu par le composant
avec lequel l’utilisateur interagit (par exemple un bouton, un curseur, un
textField, etc.). Un traitement d’événement est une méthode qui reçoit un
objet Event de façon à ce que le programme puisse traiter l’interaction de
l’utilisateur.

Rappels : AWT 4/65


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Modèle d’événements JDK 1.1

Modèle de délégation (JDK 1.1)


JDK 1.1 a introduit un nouveau modèle d’événement appelé modèle
d’événement par délégation. Dans un modèle d’événement par
délégation, les événements sont envoyés au composant, mais c’est à
chaque composant d’enregistrer une routine de traitement d’événement
(appelé veilleur: Listener) pour recevoir l’événement. De cette façon, le
traitement d’événement peut figurer dans une classe distincte du
composant. Le traitement de l’événement est ensuite délégué à une classe
séparée.

Applet Panel et Applet


Traitements d’événements
Panel
événement action
Bouton Traitement d’actio
actionPerformed(ActionEvent
....
}

Rappels : AWT 4/66


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
modèle d’événements JDK 1.1

Les événements sont des objets qui ne sont renvoyés qu’aux veilleurs
enregistrés. A chaque type d’événement est associé une interface d’écoute
correspondante.

A titre d’exemple, voici un cadre simple comportant un seul bouton :


import java.awt.*;
public class TestButton {
public static void main (String args[]){
Frame f = new Frame ("Test");
Button b = new Button("Press Me!");
b.addActionListener(new ButtonHandler());
f.add(b,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
}

La classe ButtonHandler défini une instance de traitement de l’événement


.
import java.awt.event.*;
public class ButtonHandler implements
ActionListener{
public void actionPerformed(ActionEvent e) {
System.out.println("Action occured");
}
}

Rappels : AWT 4/67


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Modèle d’événements JDK 1.1

Modèle de délégation (JDK 1.1) (suite)


• La classe Button comporte une méthode
addActionListener(ActionListener).

• L’interface ActionListener définit une méthode simple,


actionPerformed qui recevra un ActionEvent.

• Lorsqu’un objet de la classe Button est créé, l’objet peut


enregistrer un veilleur pour les ActionEvent par l’intermédiaire
de la méthode addActionListener, en précisant la classe d’objets
qui implémente l’interface ActionListener.

• Lorsque l’on clique sur l’objet Bouton avec la souris, un


ActionEvent est envoyé à chaque ActionListener enregistré par
l’intermédiaire de la méthode actionPerformed (ActionEvent).

Rappels : AWT 4/68


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
modèle d’événements JDK 1.1

Modèle de délégation (JDK 1.1) (suite)


Cette approche présente plusieurs avantages :

• Il est possible de créer des classes de filtres pour classifier les


événements .

• Le modèle de délégation est plus adapté à la répartition du travail


entre les classes.

• Le nouveau modèle d’événement supporte Java BeansTM.

Certains problèmes/inconvénients du modèle méritent également d’être


considérés :

• Il est plus difficile à comprendre, au moins au départ.

• Le passage du code JDK 1.0 au code JDK 1.1 est compliqué.

• Bien que la version actuelle de JDK gère le modèle d’événement


JDK 1.0 en plus du modèle de délégation, les modèles
d’événements JDK 1.0 et JDK 1.1 ne peuvent pas être mélangés.

Rappels : AWT 4/69


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Comportement de l’interface graphique utilisateur Java

Catégories d’événements
Le mécanisme général de réception des événements à partir de
composants a été décrit dans le contexte d’un seul type d’événement.
Plusieurs événements sont définis dans le package java.awt.event, et
des composants tiers peuvent s’ajouter à cette liste.

Pour chaque catégorie d’événements, il existe une interface qui doit être
implémentée par toute classe souhaitant recevoir ces événements. Cette
interface exige aussi qu’une ou plusieurs méthodes soient définies. Ces
méthodes sont appelées lorsque des événements particuliers surviennent.
Le tableau de la page suivante liste les catégories et indique le nom de
l’interface correspondante ainsi que les méthodes associées. Les noms de
méthodes sont des mnémoniques indiquant les conditions générant
l’appel de la méthode.

On remarquera qu’il existe des événements de bas niveau (une touche est
pressée, on clique la souris) et des événements abstraits de haut niveau
(Action = sur un bouton on a cliqué, sur un TextField on a fait un <retour
chariot>, ...)

Rappels : AWT 4/70


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Tableaux

Category Interface Name Methods


Action ActionListener actionPerformed(ActionEvent)
Item ItemListener itemStateChanged(ItemEvent)
Mouse MotionMouseMotionListener mouseDragged(MouseEvent)
mouseMoved(MouseEvent)
Mouse MouseListener mousePressed(MouseEvent)
mouseReleased(MouseEvent)
mouseEntered(MouseEvent)
mouseExited(MouseEvent)
mouseClicked(MouseEvent)
Key KeyListener keyPressed(KeyEvent)
keyReleased(KeyEvent)
keyTyped(KeyEvent)
Focus FocusListener focusGained(FocusEvent)
focusLost(FocusEvent)
Adjustement AdjustmentListener
adjustementValueChanged(AdjustementEvent)
Component ComponentListener componentMoved(ComponentEvent)
componentHidden(ComponentEvent)
componentResize(ComponentEvent)
componentShown(ComponentEvent)

Window WindowListener windowClosing(WindowEvent)


windowOpened(WindowEvent)
windowIconified(WindowEvent)
windowDeiconified(WindowEvent)
windowClosed(WindowEvent)
windowActivated(WindowEvent)
windowDeactivated(WindowEvent)
Container ContainerListener componentAdded(ContainerEvent)
componentremoved(ContainerEvent)
Text TextListener textValueChanged(TextEvent)

Rappels : AWT 4/71


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Comportement de l’interface graphique utilisateur Java

Evénements générés par composants AWT

Table 4:

Acti mou
on com cont
adju focu mou se win
Composant AWT pon aine item key text
st s se moti dow
ent r
on

Button ● ● ● ● ● ●
Canvas ● ● ● ● ●
Checkbox ● ● ● ● ● ●
CheckboxMenuItem ●
Choice ● ● ● ● ● ●
Component ● ● ● ● ●
Container ● ● ● ● ● ●
Dialog ● ● ● ● ● ● ●
Frame ● ● ● ● ● ● ●
Label ● ● ● ● ●
List ● ● ● ● ● ● ●
MenuItem ●
Panel ● ● ● ● ● ●
Scrollbar ● ● ● ● ● ●
ScrollPane ● ● ● ● ● ●
TextArea ● ● ● ● ● ●
TextComponent ● ● ● ● ● ●
TextField ● ● ● ● ● ● ●
Window ● ● ● ● ● ● ●

Rappels : AWT 4/72


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Comportement de l’interface graphique utilisateur Java

Obtention d’informations sur un événement


Lorsque les méthodes de traitement, telles que mouseDragged() sont
appelées, elles reçoivent un argument qui peut contenir des informations
importantes sur l’événement initial. Pour savoir en détail quelles
informations sont disponibles pour chaque catégorie d’événement,
reportez-vous à la documentation relative à la classe considérée dans le
package java.awt.event.

Récepteurs multiples
La structure d’écoute des événements AWT permet actuellement
d’associer plusieurs veilleurs au même composant. En général, si on veut
écrire un programme qui effectue plusieurs actions basées sur un même
événement, il est préférable de coder ce comportement dans la méthode
de traitement.

Cependant, la conception d’un programme exige parfois que plusieurs


parties non liées du même programme réagissent au même événement.
Cette situation peut se produire si, par exemple, un système d’aide
contextuel est ajouté à un programme existant.

Le mécanisme d’écoute permet d’appeler une méthode add*Listener


aussi souvent que nécessaire en spécifiant autant d’écouteurs différents
que la conception l’exige. Les méthodes de traitement de tous les
écouteurs enregistrés sont appelées lorsque l’événement survient.


L’ordre d’appel des méthodes de traitement n’est pas défini. En général, si
cet ordre a une importance, les méthodes de traitement ne sont pas liées et
on ne doit pas utiliser cette fonction pour les appeler. Au lieu de cela, il
faut enregistrer simplement le premier écouteur et faire en sorte qu’il
appelle directement les autres. C’est ce qu’on appelle un multiplexeur
d’événements

Rappels : AWT 4/73


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Adaptateurs d’événements

Il est évident que la nécessité d’implanter toutes les méthodes de chaque


interface d’écouteur représente beaucoup de travail, en particulier pour
les interfaces MouseListener et ComponentListener.

A titre d’exemple, l’interface MouseListener définit les méthodes


suivantes :

• mouseClicked (MouseEvent)

• mouseEntered (MouseEvent)

• mouseExited (MouseEvent)

• mousePressed (MouseEvent)

• mouseReleased(MouseEvent)

Pour des questions pratiques, Java fournit une classe d’adaptateurs pour
pratiquement chaque interface de veiller, cette classe implante l’interface
appropriée, mais ne définit pas les actions associées à chaque méthode.

De cette façon, la routine d’écoute que l’on définit peut hériter de la classe
d’adaptateurs et ne surcharger que des méthodes choisies.

Rappels : AWT 4/74


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Adaptateurs d´événements

Par exemple :
import java.awt.*;
import.awt.event.*;

public class MouseClickHandler extends MouseAdapter {

//Nous avons seulement besoin du traitement mouseClick,


//nous utilisons donc l’adaptateur pour ne pas avoir à
//écrire toutes les méthodes de traitement d’événement

public void mouseClicked (MouseEvent e) {


//Faire quelque chose avec le clic de la souris . . .
}
}

Rappels : AWT 4/75


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Les composants :

Button
C’est un composant d’interface utilisateur de base de type "appuyer pour
activer". Il peut être construit avec une étiquette de texte précisant son
rôle .
Button b = new Button(“Sample”);
add(b);
b.addActionListener(this);

L’interface ActionListener doit pouvoir traiter un clic d’un bouton de


souris. La méthode getActionCommand() de l’événement action
(ActionEvent) activé lorsqu’on appuie sur le bouton rend par défaut la
chaîne de l’étiquette.

Rappels : AWT 4/76


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Checkbox

La case à cocher fournit un dispositif d’entrée "actif/inactif" accompagné


d’une étiquette de texte.
Checkbox one = new Checkbox("One", false);
Checkbox two = new Checkbox("Two", false);
Checkbox three = new Checkbox("Three", true);
add(one);
add(two);
add(three);
one.addItemListener(new Handler());
two.addItemListener(new Handler());
three.addItemListener(new Handler());

La sélection ou désélection d’une case à cocher est notifiée à la réalisation


de l’interface ItemListener. Pour détecter une opération de sélection ou
de déselection, il faut utiliser la méthode getStateChange() sur l’objet
ItemEvent. Cette méthode renvoie l’une des constantes
ItemEvent.DESELECTED ou ItemEvent.SELECTED, selon le cas. La
méthode getItem() renvoie un objet de type chaîne (String) qui
représente la chaîne de l’étiquette de la case à cocher considérée.
class Handler implements ItemListener {
public void itemStateChanged(ItemEvent ev) {
String state = “deselected”;
if (ev.getStateChange() == ItemEvent.SELECTED){
state = “selected”;
}
System.out.println(ev.getItem() + “ “ + state);
}
}

Rappels : AWT 4/77


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
CheckboxGroup

On peut créer des cases à cocher à l’aide d’un constructeur spécial qui
utilise un argument supplémentaire CheckboxGroup. Si on procéde ainsi,
l’aspect des cases à cocher est modifié et toutes les cases à cocher liées au
même groupe adoptent un comportement de "bouton radio".
CheckboxGroup cbg = new CheckboxGroup();
Checkbox one = new Checkbox("One", cbg, false);
Checkbox two = new Checkbox("Two", cbg, false);
Checkbox three = new Checkbox("Three", cbg, true);
add(one);
add(two);
add(three);

Rappels : AWT 4/78


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Choice

Le composant Choice fournit une outil simple de saisie de type


"sélectionner un élément dans cette liste".
Choice c = new Choice();
c.addItem("First");
c.addItem("Second");
c.addItem("Third");
c.addItemListener(. . .);

Lorsqu’un composant Choice est activé il affiche la liste des éléments qui
lui ont été ajoutés. Notez que les éléments ajoutés sont des objets de type
chaîne (String).

L’interface ItemListener sert à observer les modifications de ce choix.


Les détails sont les mêmes que pour la case à cocher. La méthode
getSelectedIndex() de Choice permet de connaître l’index
selectionné.

Rappels : AWT 4/79


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
List

Une liste permet de présenter à l’utilisateur des options de texte affichées


dans une zone où plusieurs éléments peuvent être visualisés
simultanément. Il est possible de naviguer dans la liste et d’y sélectionner
un ou plusieurs éléments simultanément (mode de sélection simple ou
multiple).
List l = new List(4, true);

L’argument numérique transmis au constructeur définit le nombre d’items


visibles. L’argument booléen indique si la liste doit permettre à
l’utilisateur d’effectuer des sélections multiples.

Un ActionEvent, géré par l’intermédiaire de l’interface


ActionListener, est généré par la liste dans les modes de sélection
simple et multiple. Les éléments sont sélectionnés dans la liste
conformément aux conventions de la plate-forme. Pour un environnement
Unix/Motif, cela signifie qu’un simple clic met en valeur une entrée dans
la liste, mais qu’un double-clic déclenche l’action correspondante.

Récupération: voir méthodes getSelectedObjects(),


getSelectedItems()

Rappels : AWT 4/80


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Canvas

Un canvas fournit un espace vide (arrière-plan coloré). Sa taille par défaut


étant zéro par zéro, on doit généralement s’assurer que le gestionnaire de
disposition lui affectera une taille non nulle.

Cet espace peut être utilisé pour dessiner, recevoir du texte ou des saisies
en provenance du clavier ou de la souris.

Le canvas est généralement utilisé tel quel pour fournir un espace de


dessin général.

Le canvas peut écouter tous les événements applicables à un composant


général. On peut, en particulier, lui associer des objets KeyListener,
MouseMotionListener ou MouseListener pour lui permettre de
répondre d’une façon ou d’une autre à une interaction utilisateur.

Rappels : AWT 4/81


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Label

Un label affiche une seule ligne de texte. Le programme peut modifier le


texte. Aucune bordure ou autre décoration particulière n’est utilisée pour
délimiter un label.
Label lab = new Label(“Hello”);
add(lab);

MaFrame

En général, on ne s’attend pas à ce que les Labels traitent des


événements, pourtant ils effectuent cette opération de la même façon
qu’un canvas. Dans ce cas, on ne peut capter les activations de touches de
façon fiable qu’en faisant appel à requestFocus().

Rappels : AWT 4/82


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
TextArea

La zone de texte est un dispositif de saisie de texte multi-lignes, multi-


colonnes. On peut le rendre non éditable par l’intermédiaire de la
méthode setEditable(boolean). Il affiche des barres de défilement
horizontales et verticales.
TextArea t = new TextArea(“Hello!”, 4, 30);
add(t);

On peut ajouter des veilleurs d’événements de divers type dans une zone
de texte.

Le texte étant multi-lignes, le fait d’appuyer sur <Entrée> place seulement


un autre caractère dans la mémoire tampon. Si on a besoin de savoir à
quel moment une saisie est terminée, on peut placer un bouton de
validation à côté d’une zone de texte pour permettre à l’utilisateur de
fournir cette information.

Un veilleur KeyListener permet de traiter chaque caractère entré en


association avec la méthode getKeyChar(), getKeyCode() de la classe
KeyEvent.

Rappels : AWT 4/83


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
TextField

Le TextField est un dispositif de saisie de texte sur une seule ligne.


TextField f = new TextField(“Single line”, 30);
add(f);

Du fait qu’une seule ligne est possible, un écouteur d’action


(ActionListener) peut être informé, via actionPerformed(), lorsque la
touche <Entrée> ou <Retour> est activée.

Comme la zone de texte, le champ texte peut être en lecture seule. Il


n’affiche pas de barres de défilement dans l’une ou l’autre direction mais
permet, si besoin est, un défilement de gauche à droite d’un texte trop
long.

TextComponent
La classe TextComponent dont dérivent TextField et TextArea fourni
un grand nombre de méthodes.

On a vu que les constructeurs des classes TextArea et TextField


permettent de définir un nombre de colonnes pour l’affichage. Le nombre
de colonnes est interprété en fonction de la largeur moyenne des
caractères dans la police utilisée. Le nombre de caractères effectivement
affichés peut varier radicalement en cas d’utilisation d’une police à chasse
proportionnellel.

Rappels : AWT 4/84


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Frame

C’est la fenêtre générale de "plus haut niveau". Elle possède des attributs
tels que : barre de titre et zones de contrôle du redimensionnement.
Frame f = new Frame(“Frame”);

La taille d’un Frame peut être définie à l’aide de la méthode setSize()


ou avec la méthode pack(). Dans ce cas le gestionnaire de disposition
calcule une taille englobant tous les composants du Frame et définit la
taille de ce dernier en conséquence.

Les événements du Frame peuvent être surveillés à l’aide de tous les


gestionnaires d’événements applicables aux composants généraux.
WindowListener peut être utilisé pour réagir, via la méthode
windowClosing(), lorsque le bouton Quit a été activé dans le menu du
gestionnaire de fenêtres.

Il n’est pas conseillé d’écouter des événements clavier directement à partir


d’un Frame. Bien que la technique décrite pour les composants de type
Canvas et Label, à savoir l’appel de requestFocus(), fonctionne
parfois, elle n’est pas fiable. Si on a besoin de suivre des événements
clavier, il est plutôt recommandé d’ajouter au Frame un Canvas, Panel,
etc., et d’associer le gestionnaire d’événement à ce dernier.

Rappels : AWT 4/85


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Panel

C’est le conteneur de base. Il ne peut pas être utilisé de façon isolée


comme les Frames, les fenêtres et les boîtes de dialogue.
Panel p = new Panel();

Les Panels peuvent gérer les événements (rappel : le focus clavier doit
être demandé explicitement).

Rappels : AWT 4/86


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Dialog

Un Dialog est une fenêtre qui diffère toutefois d’un Frame :

• elle est destinée à afficher des messsages fugitifs

• elle peut être modale: elle recevra systématiquement toutes les


saisies jusqu’à fermeture.

• elle ne peut-être supprimée ou icônifiée par les boutons du


gestionnaire de fenêtre, on lui associe habituellement un bouton
de validation.

Dialog d = new Dialog(f, "Dialog", false);


d.add(new Label("Hello, I'm a Dialog"),
BorderLayout.CENTER);
d.pack();

Rappels : AWT 4/87


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Dialog

Un dialog dépend d’une Frame : cette Frame apparait comme premier


argument dans les constructeurs de la classe Dialog.

Les boîtes de dialogue ne sont pas visibles lors de leur création.Elles


s’affichent plutôt en réponse à une autre action au sein de l’interface
utilisateur, comme le fait d’appuyer sur un bouton.
public void actionPerformed(ActionEvent ev) {
d.setVisible(true);
}


Il est recommandé de considérer une boîte de dialogue comme un
dispositif réutilisable. Ainsi, vous ne devez pas détruire l’objet individuel
lorsqu’il est effacé de l’écran, mais le conserver pour une réutilisation
ultérieure.

Pour masquer une boîte de dialogue, appelez setVisible(false). Cette


opération s’effectue généralement en ajoutant un WindowListener, et en
attendant que la méthode windowClosing() soit appelée dans ce
gestionnaire d’événement.

Rappels : AWT 4/88


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
FileDialog

C’est une implantation d’un dispositif de sélection de fichier. Elle


comporte sa propre fenêtre autonome et permet à l’utilisateur de
parcourir le système de fichiers et de sélectionner un fichier spécifique
pour des opérations ultérieures.
FileDialog d = new FileDialog(f, "FileDialog");
d.setVisible(true);
String fname = d.getFile();

En général, il n’est pas nécessaire de gérer des événements à partir de la


boîte de dialogue de fichiers. L’appel de setVisible(true) se bloque
jusqu’à ce que l’utilisateur sélectionne OK. Le fichier sélectionné est
renvoyé sous forme de chaîne .Voir getDirectory(), getFile()

Rappels : AWT 4/89


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
ScrollPane

Fournit un conteneur général ne pouvant pas être utilisé de façon


autonome. Il fournit une vue sur une zone plus large et des barres de
défilement pour manipuler cette vue.
Frame f = new Frame("ScrollPane");
Panel p = new Panel();
ScrollPane sp = new ScrollPane();
p.setLayout(new GridLayout(3, 4));
sp.add(p);
f.add(sp);
f.setSize(200, 200);
f.setVisible(true);

Le ScrollPane crée et gère les barres de défilement selon les besoins. Il


contient un seul composant et on ne peut pas influer sur le gestionnaire
de disposition qu’il utilise. Au lieu de cela, on doit lui ajouter un Panel,
configurer le gestionnaire de disposition de ce Panel et placer les
composants à l’intérieur de ce dernier.

En général, on ne gère pas d’événements dans un ScrollPane, mais on


le fait dans les composants qu’il contient.

Rappels : AWT 4/90


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Menus

Les menus diffèrent des autres composants par un aspect essentiel. En


général, on ne peut pas ajouter de menus à des conteneurs ordinaires et
laisser le gestionnaire de disposition les gérer. On peut seulement ajouter
des menus à des éléments spécifiques appelés conteneurs de menus.
Généralement, on ne peut démarrer une "arborescence de menu" qu’en
plaçant une barre de menus dans un Frame via la méthode
setMenuBar(). A partir de là, on peut ajouter des menus à la barre de
menus et incorporer des menus ou éléments de menu à ces menus.

L’exception est le menu PopUpMenu qui peut être ajouté à n’importe quel
composant, mais dans ce cas précis, il n’est pas question de disposition à
proprement parler.

Menu Aide
Une caractéristique particulière de la barre de menus est que l’on peut
désigner un menu comme le menu Aide. Cette opération s’effectue par
l’intermédiaire de la méthode setHelpMenu(Menu). Le menu à considérer
comme le menu Aide doit avoir été ajouté à la barre de menus, et il sera
ensuite traité de la façon appropriée pour un menu Aide sur la plate-
forme locale. Pour les systèmes de type X/Motif, cela consiste à décaler
l’entrée de menu à l’extrémité droite de la barre de menus.

Rappels : AWT 4/91


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
MenuBar

C’est la barre de menu horizontale. Elle peut seulement être ajouté à


l’objet Frame et constitue la racine de toutes les arborescences de menus.
Frame f = new Frame(“MenuBar”);
MenuBar mb = new MenuBar();
f.setMenuBar(mb);

MenuBar

Menu Menu

MenuItem MenuItem

Rappels : AWT 4/92


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Menu

La classe Menu fournit le menu déroulant de base. Elle peut être ajoutée à
une barre de menus ou à un autre menu.
MenuBar mb = new MenuBar();
Menu m1 = new Menu("File");
Menu m2 = new Menu("Edit");
Menu m3 = new Menu("Help");
mb.add(m1);
mb.add(m2);
mb.add(m3);
mb.setHelpMenu(m3);


Les menus présentés ici sont vides ce qui explique l’aspect du menu File.

On peut ajouter un ActionListener à un objet Menu, mais c’est assez


inhabituel. Normalement, les menus servent seulement à disposer des
MenuItem décrits plus loin.

Rappels : AWT 4/93


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
MenuItem

Les éléments de menu MenuItem sont les “feuilles” d’une arborescence


de menu.
Menu m1 = new Menu("File");
MenuItem mi1 = new MenuItem("Save");
MenuItem mi2 = new MenuItem("Load");
MenuItem mi3 = new MenuItem("Quit");
m1.add(mi1);
m1.add(mi2);
m1.addSeparator();
m1.add(mi3);

En règle générale, on ajoute un ActionListener aux objets MenuItem


afin d’associer des comportements aux menus.

Rappels : AWT 4/94


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
CheckboxMenuItem

Les éléments de menu à cocher permettent de proposer des sélections


(activé/désactivé) dans les menus.
Menu m1 = new Menu("File");
MenuItem mi1 = new MenuItem("Save");
CheckboxMenuItem mi2 =
new CheckboxMenuItem("Persistent");
m1.add(mi1);
m1.add(mi2);

L’élément de menu à cocher doit être surveillé via l’interface ItemListener.


C’est pourquoi la méthode itemStateChanged() est appelée lorsque l’état
de l’élément à cocher est modifié.

Rappels : AWT 4/95


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
PopupMenu

Fournit un menu autonome pouvant s’afficher instantanément sur un


autre composant. On peut ajouter des menus ou éléments de menu à un
menu instantané.
Frame f = new Frame("PopupMenu");
Button b = new Button("Press Me");
b.addActionListener(...);

PopupMenu p = new PopupMenu("Popup");


MenuItem s = new MenuItem("Save");
MenuItem l = new MenuItem("Load");

s.addActionListener(...);
l.addActionListener(...);

f.add("Center", b);
p.add(s);
p.add(l);
f.add(p);

Rappels : AWT 4/96


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
PopupMenu (suite)


Le menu PopUp doit être ajouté à un composant "parent". Cette opération
diffère de l’ajout de composants ordinaires à des conteneurs. Dans
l’exemple suivant, le menu instantané a été ajouté au Frame englobant.

Pour provoquer l’affichage du menu instantané, on doit appeler la


méthode show. L’affichage nécessite qu’une référence à un composant
joue le rôle d’origine pour les coordonnées x et y.

Dans cet exemple c’est le composant b qui sert de référence.


public void actionPerformed(ActionEvent ev) {
p.show(b, 10, 10);
}

Composant de référence pour


l’affichage du popup menu

Coordonnées % composantes
d’origines


Le composant d’origine doit être sous (ou contenu dans) le composant
parent dans la hiérarchie des composants.

Rappels : AWT 4/97


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Contrôle des aspects visuels

On peut contrôler l’apparence des composants AWT en matière de


couleur de fond et de premier plan ainsi que de police utilisée pour le
texte.

Couleurs
Deux méthodes permettent de définir les couleurs d’un composant :

• setForeground(...)

• setBackground(...)

Ces deux méthodes utilisent un argument qui est une instance de la classe
java.awt.Color. On peut utiliser des couleurs de constante désignées
par Color.red Color.blue etc. La gamme complète de couleurs
prédéfinies est documentée dans la page relative à la classe Color.

Qui plus est, on peutcréer une couleur spécifique de la façon suivante :


int r = 255, g = 255, b = 0;
Color c = new Color(r, g, b);

Un tel constructeur crée une couleur d’après les intensités de rouge, vert
et bleu spécifiées sur une échelle allant de 0 à 255 pour chacune.

Rappels : AWT 4/98


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Contrôle des aspects visuels

Polices
La police utilisée pour afficher du texte dans un composant peut être
définie à l’aide de la méthode setFont(). L’argument utilisé pour cette
méthode doit être une instance de la classe java.awt.Font.

Aucune constante n’est définie pour les polices, mais on peut créer une
police en indiquant son nom, son style et sa taille en points.
Font f = new Font(“TimesRoman”, Font.PLAIN, 14);

Voici quelques noms de polices valides :

• Dialog

• SansSerif (remplace Helvetica)

• Serif (remplace TimesRoman )

• Monospaced (remplace Courier)

On peut obtenir la liste complète des polices en appelant la méthode


getFontList() de la classe Toolkit. La boîte à outils (toolkit) peut être
obtenue à partir du composant, une fois ce dernier affiché on appelle la
méthode getToolkit(). On peut aussi utiliser le ToolKit par défaut
obtenu par Toolkit.getDefaultToolkit().

Rappels : AWT 4/99


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Contrôle des aspects visuels

Polices
Les constantes de style de police sont en réalité des valeurs entières (int),
parmi celles citées ci-après :

• Font.BOLD

• Font.ITALIC

• Font.PLAIN

• Font.BOLD + Font.ITALIC

Les tailles en points doivent être définies avec une valeur entière.

Rappels : AWT 4/100


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Impression

L’impression est gérée dans Java 1.1 d’une façon similaire à l’affichage sur
écran. Grace à une instance particulière de java.awt.Graphics toute
instruction de dessin dans ce contexte est en fait destinée à l’imprimante.

Le système d’impression Java 1.1 permet d’utiliser les conventions


d’impression locales, de sorte que l’utilisateur voit s’afficher une boîte de
dialogue de sélection d’imprimante lorsque l’on lance une opération
d’impression. L’utilisateur peut ensuite choisir dans cette boite de
dialogue les options telles que la taille du papier, la qualité d’impression
et l’imprimante à utiliser.
Frame f = new Frame("Print test");
Toolkit t = f.getToolkit();
PrintJob job = t.getPrintJob(f,"Mon impr.", null);
if (job != null) {
Graphics g = job.getGraphics();
.....
}

Ces lignes créent un contexte graphique (Graphics) "connecté" à


l’imprimante choisie par l’utilisateur. Pour obtenir un nouveau contexte
pour chaque page :
f.printAll(g);// ou printComponents()

On peut utiliser n’importe quelle méthode de dessin de la classe


Graphics pour écrire sur l’imprimante. Ou bien, comme indiqué ici, on
peut simplement demander à un composant de se tracer. La méthode
print() demande à un composant de se tracer , mais elle n’est liée qu’au
composant pour lequel elle a été appelée. Dans le cas d’un conteneur,
comme ici, on peut utiliser la méthode printAll() pour que le conteneur
et tous les composants qu’il contient soient tracés sur l’imprimante.
Utiliser printComponents() si on utilise des composants 100% JAVA.
g.dispose();
job.end();

Après avoir créé une page de sortie conforme à ce que l’on souhaite, on
utilise la méthode dispose() pour que cette page soit soumise à
l’imprimante.

Rappels : AWT 4/101


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
4
Impression

Une fois ce travail terminé, on appele la méthode end() sur l’objet tâche
d’impression. Elle indique que la tâche d’impression est terminée et
permet au système de traitement en différé d’exécuter réellement la tâche
puis de libérer l’imprimante pour d’autres tâches.

Nota: Dans le contexte Solaris il n’existe pas d’objet standard de menu


d’impression. On peut utiliser le 3ème argument de getPrintJob() qui
est un dictionnaire de propriétés (qui peut aussi être null
Frame f = new Frame("Print test");
Toolkit t = f.getToolkit();
Properties pprops = new Properties();
pprops.put("awt.print.paperSize","a4");
pprops.put("awt.print.orientation","landscape");
PrintJob job = t.getPrintJob(f,"Mon impr.", pprops);
.....

Les propriétés de ce dictionnaire sont :


awt.print.destination
awt.print.printer
awt.print.fileName
awt.print.options
awt.print.orientation (portrait, landscape)
awt.print.paperSize (letter,legal,executive,a4)
awt.print.numCopies

Rappels : AWT 4/102


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
Rappels: Flots E/S, linéarisation 5

Objet
Rappels des notions fondamentales sur les Entrées/Sorties JAVA:

• Flots (Streams)

• I/OStreams et Reader/Writer

• catégories de flots

• filtres

• fichiers

Rappels spécifiques sur la linéarisation:

• Data Input/Output

• Object Input/Output

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
E/S JAVA : concepts fondamentaux

Pour pouvoir être réalisés de manière portable sur tous les systèmes les
Entrés/Sorties Java s’appuient sur des concepts abstraits de haut niveau.

flots d’E/S (Streams)


Un flot de données (Stream) est un dispositif qui permet d’accéder
séquentiellement des données. Dans un flot d’entrée on consomme
successivement ces données et dans un flot de sortie on les envoie.

Une abstraction comme un InputStream lit des octets et dispose d’un


petit nombre de méthodes fondamentales comme:
int read()
int read(byte[])
int read(byte[], int, int)

La méthode read renvoie un argument int contenant un octet lu à partir


du flot ou la valeur -1 indiquant la fin de fichier. Les deux autres
méthodes lisent dans une buffer de byte et renvoient le nombre d’octets
lus.
void close()

permet de fermer le flot.

D’autre méthodes permettent de "sauter" un nombre d’octets déterminé


ou même, si c’est possible, de "marquer" un emplacement, de faire des
lectures anticipées et de revenir ensuite à la marque initiale.

Rappels: Flots E/S, linéarisation 5/104


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
E/S JAVA : concepts fondamentaux

I/O Streams et Reader/Writer


Au niveau des flots fondamentaux de bas niveau on distingue d’une part
les I/OStream qui manipulent des octets (byte) et les Reader et Writer
qui manipulent des caractères. Comme JAVA utilise des caractères 16 bits
UNICODE les réalisations de base ne sont pas les même pour ces deux
catégories.

Une situation particulière est celle où on est au confluent des mondes


JAVA (avec des caractères UNICODE) et non-JAVA (avec un codage d’un
autre type). Les classes InputStreamReader et OutputStreamWriter
disposent de convertisseurs qui permettent d’assurer un fonctionnement
corrects des flots. Il faut toutefois veiller à spécifier correctement le type
de conversion (qui, par défaut, est déduit de l’environnement local)

catégories de flots
Parmi les classes de l’API JAVA on peut classifier les flots selon:

• leur structure d’origine (c.a.d. l’endroit d’où proviennent les don-


nées) : buffers (ByteArrayInputStream, CharArrayReader,
StringReader,...), threads (PipedInputStream, PipedRea-
der), fichiers (FileInputStream, FileReader), flots de
communications produits par des Socket, URL, Process, etc.
(InputStream produits par les méthodes getInputStream())
ou même regroupement de Streams (SequenceInputStream)

• les particularités de leur mode de fonctionnement: bufferisation


(BufferedInputStream, BufferedReader), possibilité de ré-
pudiation de lecture (PushbackInputStream,
PushbackReader), formattages particulier (DataInputStream,
ObjectInputStream, GZIPInputStream, PrintWriter,
StreamTokenizer...)

L’architecture des héritages est particulièrement complexe à appréhender


mais la notion centrale est celle de filtre (exemple :
FilterInputStream)

Rappels: Flots E/S, linéarisation 5/105


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
E/S JAVA : concepts fondamentaux

filtres
De nombreuses classes d’E/S -et, en particulier, les classes de type
Filter* (FilterInputStream, FilterReader,..)- sont des
adaptateurs qui permettent de combiner les caractéristiques de plusieurs
classes d’Entrées/Sorties.

On peut ainsi contruire une instance de flot qui enchaîne différents


services d’E/S :
String str ;
BufferedReader inr =
new BufferedReader(new InputStreamReader(System.in);
while ((str = in.readLine()) != null) {
System.out.println("Read: " + str);
}

La construction ci-dessus (un filtre bufferisé avec conversion de caractères


du codage local vers UNICODE) est rendu possible par le fait que les
constructeurs des classes admettent en paramètre un ancêtre commun
(Reader pour BufferedReader, InputStream pour
InputStreamReader,...)

Rappels: Flots E/S, linéarisation 5/106


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
Fichiers

La classe File est un abstraction permettant de créer, manipuler des


fichiers ou d’obtenir des informations sur ces fichiers.

Noms de fichiers

• String getName()

• String getPath()

• String getAbsolutePath()

• String getParent()

• boolean renameTo(File newName)

Tests de fichiers

• boolean exists()

• boolean canWrite()

• boolean canRead()

• boolean isFile()

• boolean isDirectory()

• boolean isAbsolute();

Information générale axée sur les fichiers et utilitaires

• long lastModified()

• long length()

• boolean delete()

Utilitaires en rapport avec les répertoires

• boolean mkdir()

• String[] list()

Rappels: Flots E/S, linéarisation 5/107


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
Linéarisation

Classes DataInputStream etDataOutputStream


Ces flots permettent la lecture et l’écriture de types de base Java. Voici une
palette de méthodes :

Méthodes DataInputStream

byte readByte()
boolean readBoolean()
char readChar()
short readShort()
int readUnsignedShort()
int readInt()
long readLong()
float readFloat()
double readDouble()
String readUTF()

DataOutputStream fourni les méthodes d’écriture correspondantes.

Les méthodes *UTF permettent de lire/écrire des chaînes de caractères


UNICODE en restant dans le monde JAVA. Elles utilisent un type de
codage particulier (UTF8) qui permet de condenser des chaînes
UNICODE lors d’un transfert sur une ligne de communication.

Rappels: Flots E/S, linéarisation 5/108


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
Linéarisation

Bibliographie
voit documentation

http://chatsubo.sun.com/current/serial/index.html

Object Input/Output
L’interface API de linéarisation d’objet Java fournit un moyen simple et
transparent permettant de transférer des objets JAVA ou de les conserver
dans un fichier.

L’API fournit des méthodes permettant de générer et d’exploiter ce flot.


Les objets que l’on souhaite utiliser sous forme de structures à linéariser
réalisent une interface permettant d’enregistrer ou de récupérer le contenu
de l’objet en un seul flot. Il s’agit des interfaces java.io.ObjectOutput
et java.io.ObjectInput..

Rappels: Flots E/S, linéarisation 5/109


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
Architecture de linéarisation

Package java.io
L’API de linéarisation est basée sur des interfaces conçues pour introduire
ou extraire des objets (ou des types scalaires) d’un flot d’E/S..

java.io.DataOutput java.io.OutputStream

ObjectOutput ObjectOutputStream

ObjectStreamConstants

java.io.DataInput java.io.InputStream

ObjectInput ObjectInputStream

java.lang.Object

java.io.Serializable
Légende
Classe
Classe abstraite
Interface
java.io.Externalizable Etend
Implante

Rappels: Flots E/S, linéarisation 5/110


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
Architecture de linéarisation

Interface Serializable
L’interface Serializable sert à identifier les classes pouvant être
linéarisées.

Toute classe peut être linéarisée dans la mesure où elle satisfait aux
critères suivants :

• La classe (ou une classe de la hiérarchie de cette classe) doit


implémenter java.io.Serializable.

• Les champs à ne pas linéariser doivent être repérés à l’aide du mot


clé transient. Parmi ces champs, citons les classes
java.io.FileInputStream, java.io.FileOutputStream et
java.lang.Threads. Si le mot clé transient n’est pas affecté à
ces champs, une tentative d’appel de la méthode writeObject()
générera une exception NotSerializableException.

Eléments sérialisables
Tous les champs (données) d’un objet Serializable sont écrits dans le
flot. Sont concernés les types scalaires, les tableaux et les références à
d’autres objets.

Les champs statiques ne sont pas linéarisés.

Il est à noter que le mécanisme d’accès aux champs (private, protected


et public) n’a aucun effet sur le champ en cours de linéarisation. Si
nécessaire on doit déclarer les champs private en tant que private
transient.

Rappels: Flots E/S, linéarisation 5/111


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
Ecriture et lecture d’un flot d’objets

Ecriture
L’écriture et la lecture d’un objet dans un flot de fichiers est un processus
simple. Examinons le fragment de code suivant qui transmet une instance
d’un objet java.util.Date à un fichier :
Date d = new Date();
FileOutputStream f = new FileOutputStream("date.ser");
ObjectOutputStream s = new ObjectOutputStream (f);
try {
s.writeObject (d);
s.close ();
} catch (IOException e) {
e.printStackTrace();
}

Lecture
La lecture de l’objet est aussi simple que l’écriture, à une exception près —
la méthode readObject() retourne le flot sous forme de type Object et
elle doit être associée au nom de classe correspondant, avant que
l’exécution des méthodes sur cette classe soit possible :
Date d = null;
FileInputStream f = new FileInputStream ("date.ser");
ObjectInputStream s = new ObjectInputStream (f);
try {
d = (Date)s.readObject ();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println ("Date serialized at: "+ d);

Rappels: Flots E/S, linéarisation 5/112


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
Architecture de linéarisation

qu’est ce qui est transferré?


Le transfert d’un objet suppose la conservation :

• de la désignation de la classe,

• de sa "signature"

• des valeurs des champs non-statiques et non-transient (y compris


les objets référencés)

Cela implique :

• que le correspondant connaisse la classe désignée pour pouvoir la


reconstituer.

• que la classe connue par le correspondant soit compatible avec la


version de la classe expédiée. La signature de la classe (voir
utilitaire serialver) donne un identifiant caractérisant la
version. Dans la spécification du langage JAVA des règles
complexes définisse la compatibilité entre deux versions d’une
même classe.

• que le Stream courant garde trace des identifiants d’instances


transférées. Ceci a plusieurs conséquences :

• linéariser un objet peut entraîner la linéarisation d’un graphe


complexe de références (on prendra soin de mettre de
nombreux champs à transient si on ne veux pas transférer
par inadvertance un grand nombre d’objets)

• le graphe des références est reconstitué correctement à l’arrivée


(même s’il y a des cycles!).Cette complexité peut conduire à des
performances faibles du transfert

• si le Stream est fermé puis réouvert on perd la trace correcte


des instances (voir connexions client/serveur). Par contre si le
Stream reste ouvert il est impossible de transférer
successivement une même instance dans laquelle il y a
modification de valeurs de champs.

Rappels: Flots E/S, linéarisation 5/113


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
Architecture de linéarisation

personnalisation de la lecture/écriture d’objet


On peut personnaliser la linéarisation d’une classe en définissant deux
méthodes privées writeObject and readObject.

La méthode writeObject permet de contrôler quelles informations sont


sauvegardées. Typiquement on l’utilise pour envoyer des informations
complémentaires qui permettront de reconstituer correctement l’objet à
l’arrivée : supposons par exemple qu’on ait des deux cotés un mécanisme
de dictionnaire (ou de base de données) qui permette de rechercher un
objet en connaissant une clef; au lieu de transférer cet objet (qui est
référencé par l’objet courant) on peut transférer sa clef et le reconstituer à
l’arrivée en consultant le dictionnaire.
private void writeObject(ObjectOutputStream s)
throws IOException {
s.defaultWriteObject();
// code spécifique
}

La méthode readObject doit être soigneusement conçue pour lire


exactement les données dans le même ordre.
private void readObject(ObjectInputStream s)
throws IOException {
s.defaultReadObject();
//lecture des données personnalisées
...
// code de mise à jour de l’instance courante
}

Les méthodes writeObject et readObjectne sont responsables que de


la linéarisation de la classe courante. Toute linéarisation de super-classe
est traitée automatiquement. Si on a besoin de coordination explicite avec
la super-classe il vaut mieux passer par le mécanisme de l’interface
Externalizable.

Rappels: Flots E/S, linéarisation 5/114


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5
Architecture de linéarisation

Externalisable
Les classes implantant l’interface Externalizable, prennent la
responsabilité du stockage et de la récupération de l’état de l’objet lui-
même.
package java.io;

public interface Externalizable extends Serializable {

public void writeExternal (ObjectOutput out)


throws IOException;

public void readExternal (ObjectInput in)


throws IOException, ClassNotFoundException;
}

Les objets externalisables doivent :

• Implémenter l’interface java.io.Externalizable.

• Implanter une méthode writeExternal pour enregistrer l’état de


l’objet. La méthode doit explicitement correspondre au supertype
pour conserver son état.

• Implanter une méthode readExternal pour lire les données du


flot et restaurer l’état de l’objet. La méthode doit explicitement
correspondre au supertype pour conserver son état.

• Etre responsables du format défini en externe. Les méthodes


writeExternal et readExternal sont uniquement responsables
de ce format.

Des classes externalisables impliquent que la classe soit Serializable,


mais vous devez fournir les méthodes de lecture et d’écriture d’objets.
Aucune méthode n’est fournie par défaut.

ATTENTION: les mécanismes d’externalisation sont une menace pour la


sécurité! Il est recommandé de les utiliser avec une extrème prudence!

Rappels: Flots E/S, linéarisation 5/115


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
5

Rappels: Flots E/S, linéarisation 5/116


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
Rappels : Programmation réseau Java 6

Objectifs
Rappels :

• Créer un code serveur sous TCP/IP.

• Créer un code client sous TCP/IP.

• utiliser UDP

• utiliser UDP en diffusion ("multicast")

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
Programmation réseau sous Java

Sockets
Les Sockets sont des points d’entrée de communication bi-directionnelle
entre deux applications sur un réseau.

Les différents types de Socket conditionnent la façon dont les données


vont être transférées :

• Stream sockets (TCP) – Permettent d’établir une communication


en mode connecté. Un flot continu est établi entre les deux
correspondants : les données arrivent dans un ordre correct et sans
être corrompues.

• Datagram sockets (UDP) – Permettent d’établir une connexion en


mode non-connecté, que l’on appelle aussi mode Datagramme. Les
données doivent être assemblées et envoyées sous la forme de
paquets indépendants de toute connexion. Un service non
connecté est généralement plus rapide qu’un servcie connecté,
mais il est aussi moins fiable : aucune garantie ne peut être émise
quand au fait que les paquets seront effectivement distribués
correctement -ils peuvent être perdus, dupliqués ou distribués
dans le désordre-.

Rappels : Programmation réseau Java 6/118


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
Le modèle réseau de Java.

Dans Java, les sockets TCP/IP sont implantées au travers de classes du


package java.net. Voici la façon dont ces classes sont utilisées.

Serveur

Enregistrer
ServerSocket (port #, nb_cnx) ce service. Client

accept() Attendre une


connexion du Socket (host, port#)
retourne un objet Socket client. (attempt to connect)

Utiliser la Socket

InputStream OutputStream

OutputStream InputStream

close () close ()

Dans ce modèle, le fonctionnement est le suivant :

• Le Serveur enregistre son service sous un numéro de port,


indiquant le nombre de client qu’il accepte de faire "bufferiser" à
un instant T. Puis, le serveur se met en attente sur ce service par la
méthode accept() de son instance de ServerSocket.

• Le client peut alors établir une connexion avec le serveur en


demandant la création d’une socket à destination du serveur pour
le port sur lequel le service a été enregistré.

• Le serveur sort de son accept() et récupère une Socket en


communication avec le Client. Ils peuvent alors utiliser des
InputStream et OutputStream pour échanger des données.

Rappels : Programmation réseau Java 6/119


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
Principe d’un Serveur TCP/IP

Exemple de code de mise en oeuvre d’un serveur TCP/IP

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

public class SimpleServer {


public static void main(String args[]) {
ServerSocket s = null;
Socket s1;
String sendString = "Hello Net World!";
OutputStream s1out;
DataOutputStream dos;

// enregistrer votre service sur port 5432


try {
s = new ServerSocket(5432,5);
} catch (IOException e) { }

// boucle infinie listen/accept


while (true) {
try {
// attente d’une connexin
s1=s.accept();
// récuperér un stream d’écriture
s1out = s1.getOutputStream();
dos = new DataOutputStream (s1out);

// envoyer la chaîne!
dos.writeUTF(sendString);

// fermer la connexion mais pas l’attente de


// connexion
dos.close();
s1.close();
} catch (IOException e) { }
}
}
}

Rappels : Programmation réseau Java 6/120


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
Principe d’un Client TCP/IP

Le client correspondant :
import java.net.*;
import java.io.*;

public class SimpleClient {


public static void main(String[] args)
throws IOException {
int c;
Socket s1;
InputStream s1In;
DataInputStream dis;

// votre connection à args[0]t, sur port 5432


s1 = new Socket(args[0],5432);
✓ The above statement could potentially throw an IOException.

// récupération d’un stream en lecture


s1In = s1.getInputStream();
dis = new DataInputStream(s1In);

String st = new String (dis.readUTF());


System.out.println(st);

// on coupe la connexion
s1.close();
}

Rappels : Programmation réseau Java 6/121


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
échanges UDP

On n’a pas ici de connexion ouverte en permanence. Les paquets,


autonomes, sont transférés avec leur propres informations d’adresse. Le
service n’est pas "fiable" car il y a des risques de perte, ou de duplication
de paquets. L’ordre d’arrivée n’est pas garanti.
Pour limiter les incidents il vaut mieux limiter la taille des paquets
envoyés de manière à ce qu’ils n’occupent qu’un seul paquet IP.

Les objets fondamentaux :

• DatagramSocket : détermine un canal (socket) UDP. Pour un


serveur on précisera le port (pas nécessaire pour le client)
DatagramSocket serverSock = new DatagramSocket(9789);
DatagramSocket clientSock= new DatagramSocket() ;

• DatagramPacket : structure d’accueil des données et des


informations d’adresse.
Les methodes getData(), getAddress(), getPort() permettent
de récupérer ces informations.
// pour un envoi
sendPack = new DatagramPacket(byteBuff, len, addr, port);
socket.send(sendPack) ;
// pour une reception
revPack = new DatagramPacket(byteBuffer, len) ;
socket.receive(recvPack);

• InetAddress : permet de produite une adresse inet à partir


d’une désignation (méthode getByName()) ou de la machine
locale (getLocalHost())

Rappels : Programmation réseau Java 6/122


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
Exemple de Serveur UDP

Ce serveur reçoit un objet d’un client et le renvoie suivi d’un


java.sql.Timestamp.

On utilise les données d’adressage du paquet reçu du client pour


reexpédier les données

1import java.io.* ;
2 import java.net.* ;
3 import java.sql.* ;
4
5 public class DatagServer {
6 public static final int PORT = 9999 ;
7 public static final int DATA_MAX_SIZE = 512 ;
8
9 public static void main (String[] tbArgs) {
10 byte[] recBuffer = new byte[DATA_MAX_SIZE] ;
11 try{
12 DatagramSocket veille = new DatagramSocket(PORT) ;
13 while (veille != null) {
14 DatagramPacket recvPack = new DatagramPacket(
15 recBuffer, recBuffer.length) ;
16 veille.receive(recvPack) ;
17 ObjectInputStream inz = new ObjectInputStream
18 (new ByteArrayInputStream(recvPack.getData())) ;
19 Object obj = inz.readObject() ;
20 System.out.println(obj) ;
21 ByteArrayOutputStream boz = new ByteArrayOutputStream();
22 ObjectOutputStream oz = new ObjectOutputStream (boz);
23 oz.writeObject(obj) ;
24 oz.writeObject(new Timestamp(System.currentTimeMillis()));
25 // consommation excessive de données (deux byte buffers!)
26 DatagramPacket sendPack =
27 new DatagramPacket(boz.toByteArray(), boz.size(),
28 recvPack.getAddress() ,recvPack.getPort());
29 veille.send(sendPack) ;
30 }
31 } catch (Exception exc ) {
32 System.err.println(exc) ;
33 }
34
35 }//End main

Rappels : Programmation réseau Java 6/123


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
Exemple de client UDP

Correspond au serveur précédent : on envoie un java.sql.Timestamp


et on le reçoit en echo suivi de celui du serveur.
1 import java.io.* ;
2 import java.net.* ;
3 import java.sql.* ;
4
5 public class DatagClient {
6 public static final int DATA_MAX_SIZE = 512 ;
7
8 public static void main (String[] tbArgs) {
9 byte[] recBuffer = new byte[DATA_MAX_SIZE] ;
10 try{
11 DatagramSocket socket = new DatagramSocket() ;
12 if (socket != null) {
13 ByteArrayOutputStream boz = new ByteArrayOutputStream();
14 ObjectOutputStream oz = new ObjectOutputStream (boz) ;
15 oz.writeObject(new Timestamp(System.currentTimeMillis())) ;
16 // consommation excessive de données (deux byte buffers!)
17 DatagramPacket sendPack = new DatagramPacket(
18 boz.toByteArray(), boz.size(),
19 InetAddress.getByName(tbArgs[0]),
20 DatagServer.PORT) ;
21 socket.send(sendPack) ;
22 DatagramPacket recvPack =
23 new DatagramPacket(recBuffer, recBuffer.length) ;
24 socket.receive(recvPack) ;
25 ObjectInputStream inz = new ObjectInputStream
26 (new ByteArrayInputStream(recvPack.getData())) ;
27 Object obj = inz.readObject() ;
28 System.out.println(obj) ;
29 obj = inz.readObject() ;
30 System.out.println(obj) ;
31 }
32 } catch (Exception exc ) {
33 System.err.println(exc) ;
34 }
35
36 }//End main

Rappels : Programmation réseau Java 6/124


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
UDP en diffusion (Multicast)

Une adresse de diffusion (multicast) est une adresse comprise entre


224.0.0.0 et 239.255.255.255.

Des MulticastSocket permettent de diffuser des données


simultanément à un groupe d’abonnés. Sur une telle socket on peut
s’abonner à une adresse multicast par joinGroup(InetAddress
mcastaddr) ou se désabonner par leaveGroup(InetAddress).

Le paramètre TTL de ces sockets permet de fixer le nombre maximum de


routeurs traversés - si ces routeurs le permettent- (important si on veut
limiter la diffusion à l’extérieur d’une entreprise)


Actuellement les accès "Multicast" ne sont pas autorisés dans les Applet.

Rappels : Programmation réseau Java 6/125


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
Exemple de Serveur Multicast

Diffuse un java.sql.TimeStamp toute les secondes. Les paquets ne se


transmettent pas au travers des relais réseaux (TTL = 1).
1 import java.io.* ;
2 import java.net.* ;
3 import java.sql.* ;
4
5 public class MultigServer {
6 public static final int PORT = 9999 ;
7 public static final String GROUP = "229.69.69.69" ;
8 public static final byte TTL = 1 ; // pas de saut!
9 public static final int DATA_MAX_SIZE = 512 ;
10
11 public static void main (String[] tbArgs) {
12 byte[] recBuffer = new byte[DATA_MAX_SIZE] ;
13 try{
14 MulticastSocket veille = new MulticastSocket(PORT);
15 InetAddress adrGroupe = InetAddress.getByName(GROUP) ;
16 while (veille != null) {
17 ByteArrayOutputStream boz = new ByteArrayOutputStream();
18 ObjectOutputStream oz = new ObjectOutputStream (boz) ;
19 oz.writeObject(new Timestamp(System.currentTimeMillis())) ;
20 // consommation excessive de données (deux byte buffers!)
21 DatagramPacket sendPack =
22 new DatagramPacket(boz.toByteArray(), boz.size(),
23 adrgroupe, PORT) ;
24 veille.send(sendPack, TTL) ;
25
26 try{
27 Thread.sleep(1000) ;
28 } catch (InterruptedException exc) {}
29 }
30 } catch (Exception exc ) {
31 System.err.println(exc) ;
32 }
33 }//End main
34 }
35

Rappels : Programmation réseau Java 6/126


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6
Exemple de client Multicast

Reçoit 10 objets du serveur


1 import java.io.* ;
2 import java.net.* ;
3 import java.sql.* ;
4
5 public class MultigClient {
6 public static final int DATA_MAX_SIZE = 512 ;
7
8 public static void main (String[] tbArgs) {
9 MulticastSocket socket = null;
10 InetAddress adrGroupe = null ;
11 byte[] recBuffer = new byte[DATA_MAX_SIZE] ;
12 try{
13 socket = new MulticastSocket(MultigServer.PORT) ;
14 adrGroupe = InetAddress.getByName(MultigServer.GROUP) ;
15 if (socket != null) {
16 socket.joinGroup(adrGroupe) ;
17 // danger! on reutilise le meme buffer?
18 DatagramPacket recvPack =
19 new DatagramPacket(recBuffer, recBuffer.length) ;
20 for( int ix = 0 ; ix < 10 ; ix++) {
21 socket.receive(recvPack) ;
22 ObjectInputStream inz =
23 new ObjectInputStream
24 (new ByteArrayInputStream(
25 recvPack.getData())) ;
26 Object obj = inz.readObject() ;
27 System.out.println(obj) ;
28 inz.close() ;
29 }// for
30 }
31 } catch (Exception exc ) {
32 System.err.println(exc) ;
33 }
34 finally {
35 if ( socket != null) {
36 try{ socket.leaveGroup(adrGroupe) ;
37 } catch (IOException exc) {}
38 }
39 }
40 }
41 }
42

Rappels : Programmation réseau Java 6/127


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
6

Rappels : Programmation réseau Java 6/128


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
Rappels: RMI 7

Objectifs
L’API d’invocation de méthodes à distance (RMI) permet d’écrire un code
qui accède aux objets distants comme si c’était des objets locaux.

• le présent chapitre constitue une introduction à RMI

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Bibliographie
Certaines parties de ce module sont extraites de :

• “The Java Remote Method Invocation Specification” disponible


sur

http://chatsubo.javasoft.com/current/doc/rmi-spec/
rmi-spec.ps

• “Java RMI Tutorial” disponible sur

http://chatsubo.javasoft.com/current/doc/tutorial/
rmi-getstart.ps

• “Frequently Asked Questions, RMI and Object Serialization”


disponible sur

http://chatsubo.javasoft.com/current/faq.html

Rappels: RMI 7/130


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Fonction de l’architecture RMI en Java
Réalisation

Client Serveur
Class
Application Object
Implementation

Stub rmic(compiler) Skeleton

Method call

Method Results

L’ API RMI contient une série de classes et d’interfaces permettant au


développeur d’appeler des objets distants, déjà existants dans une
application s´exécutant sur une autre machine virtuelle Java (JVM). Cette
JVM “distante” ou “serveur” peut être exécutée sur la même machine ou
sur une machine entièrement différente du “client” RMI. L’architecture
RMI en Java est un mécanisme utilisant uniquement le langage Java.

Rappels: RMI 7/131


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Packages et hiérarchies RMI

Package java.rmi
java.lang.SecurityManager java.lang.Object java.io.IOException

RMISecurityManager Naming RemoteException*

Légende

Remote Classe

Classe
extraite

Interface
*Bien qu’il existe davantage d’exceptions dans les packages java.rmi
et java.rmi.server , RemoteException est l’exception que vous Etend
rencontrerez le plus fréquemment.
Implante

• Naming – Cette classe “finale” est utilisée par les clients et serveurs
RMI pour communiquer avec un “aiguilleur” appelé Registre des
noms (Registry) et situé sur la machine serveur. L’application
serveur utilise les méthodes bind et rebind pour enregistrer ses
implantations d’objets auprès du Registre, alors que le programme
client utilise la méthode lookup de cette classe pour obtenir une
référence vers un objet distant.

• Remote – Cette interface doit être étendue par toutes les interfaces
client qui seront utilisées pour accéder aux implantations d’objets
distants.

• RemoteException – Cette exception doit être générée par toute


méthode déclarée dans des interfaces et des classes de réalisation
distantes. Tous les codes client doivent donc naturellement être
écrits pour traiter cette exception.

• RMISecurityManager – Cette classe permet aux applications


locales et distantes d’accéder aux classes et aux interfaces RMI.

Rappels: RMI 7/132


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Packages et hiérarchies RMI

Package java.rmi.server
java.lang.Object

Operation
LoaderHandler

RMIClassLoader ObjID

RMISocketFactory UID

java.rmi.Remote RemoteObject java.io.Serializable

RemoteStub RemoteServer java.io.PrintStream

UnicastRemoteObject
RemoteCall LogStream

RMIFailureHandler
Légende

Skeleton
Classe

Unreferenced Classe
extraite

java.io.Externalizable RemoteRef Interface

Etend

ServerRef Implante

Rappels: RMI 7/133


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Packages et hiérarchies RMI

Package java.rmi.server (suite)


• RMIClassLoader – ClassLoader sert à charger les stubs (talons) et
les skeletons d’objets distants, ainsi que les classes des arguments et
les valeurs retournées par les appels de méthodes à distance.
Lorsque RMIClassloader tente de charger des classes à partir du
réseau, une exception est générée si aucun gestionnaire de sécurité
n’est installé.

• UnicastRemoteObject – Classe parent de chaque classe distante


en RMI

Rappels: RMI 7/134


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Server Client
Open an account
Account Manager
Get current balance
Creates Deposit money
Account
Instance Withdraw money

Exemple bancaire
Pour illustrer l’utilisation de l’invocation RMI, nous allons étudier
l’exemple simple d’une banque dans laquelle on va ouvrir un compte. Les
comptes sont contrôlés par un employé de banque : le gestionnaire de
comptes.

Après avoir ouvert un compte, on peut y déposer ou en retirer de l’argent


et vérifier le solde.

Rappels: RMI 7/135


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Interfaces bancaires
Si on tente de modéliser ce problème en utilisant l’invocation RMI, on
peut créer deux interfaces Java du type suivant :

• Account.java
package rmi.bank;
interface Account extends Remote {
public float getBalance ();
public void withdraw (float money);
public void deposit (float money);
}

• AccountManager.java
package rmi.bank;
interface AccountManager extends Remote {
public Account open (String name,
float startingBalance);
}

Rappels: RMI 7/136


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Interfaces bancaires (suite)


Il est à noter que ces interfaces sont conçues de sorte que l’on utilise
l’interface AccountManager pour générer une instance d’un objet
Account. AccountManager est chargé de retourner l’instance courante
d’un objet Account si le compte existe déjà.

Cette approche de la création d’objet est un type de conception défini


dans la méthodologie de programmation par une méthode appelée
“Générateur (Factory).”1

Ce "Générateur" permet à un objet de contrôler la création d’autres objets


et, dans le cas considéré, il s’agit de la solution idéale car le gestionnaire
de comptes (AccountManager) doit contrôler la création de nouveaux
comptes. Si l’on se rendait dans la banque et on tentait d’ouvrir un autre
compte, on répondrait “Vous possédez déjà un compte dans notre
établissement. Utilisez-le.”

1. Design Patterns - Elements of Reusable Object-Oriented Software par Gamma,


Helm, Johnson et Vlissides (Editions Addison-Wesley, 1995)

Rappels: RMI 7/137


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

BankClient.java BankServer.java
Account.java AccountManagerImpl.java
(interface)

AccountManager.java AccountImpl.java
(interface)

Account %rmi registry&


%java BankClient Instance %java BankServer

Procédure
Le processus permettant de créer une application accessible à distance
dans RMI est le suivant :

1. Définir les objets distants à utiliser sous forme d’interfaces Java.

2. Créer des classes de réalisation pour les interfaces.

3. Compiler l’interface et les classes de réalisation.

4. Créer des classes stubs et skeletons à l’aide de la commande rmic


sur les classes de réalisation.

5. Créer une application serveur permettant de gérer et de compiler


les réalisations.

6. Créer et compiler un client permettant d’accéder aux objets


distants.

7. Lancer rmiregistry et l’application serveur.

8. Tester le client.

Rappels: RMI 7/138


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Interface Account
L’exemple suivant présente l’interface Account complète :
// The Account interface
// Methods for getting the account balance, depositing,
and
// withdrawing money
package rmi.bank;
import java.rmi.*;
public interface Account extends Remote {
// Get the account balance
public float getBalance () throws RemoteException;
// Deposit money to the account -
// throw an exception if the value
// is 0 or a negative number
public void deposit (float balance)
throws BadMoneyException, RemoteException;
// Withdraw money from the account -
//but throw an exception if the
// amount of the withdrawal will exceed the account
balance
public void withdraw (float balance)
throws BadMoneyException, RemoteException;
}

L’interface Account doit étendre java.rmi.Remote et être déclarée


public afin d’être rendue accessible à distance (aux clients utilisant
d’autres JVM).

Il est à noter que toutes les méthodes génèrent une exception


java.rmi.RemoteException. Cette exception apparaît lorsque
survient un problème d’accès à la méthode d’un objet distant. Les
méthodes de dépôt et de retrait génèrent également une exception
BadMoneyException indiquant qu’une valeur négative a été transmise
pour un dépôt, ou qu’une tentative de retrait supérieur au solde du
compte a été effectuée.

Rappels: RMI 7/139


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Interface AccountManager
L’interface AccountManager complète inclut :
// The Account Manager interface

// Method for creating a new Account with the user's


// name and initial account balance

package rmi.bank;

import java.rmi.*;

public interface AccountManager extends Remote {

public Account open (String name, float


initialBalance)
throws BadMoneyException, RemoteException;

Rappels: RMI 7/140


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

réalisation de l’interface Account — AccountImpl


L’interface Account est réalisée par une classe devant à son tour
implanter toutes les méthodes définies dans Account et étendre
UnicastRemoteObject. Par convention, pour les classes réalisant des
contrats d’ interface RMI, le suffixe “Impl” sera ajouté au nom du fichier
d’interface :
// AccountImpl - Implementation of the Account interface
//
// This class is an instance of an Account and implements
// the balance, deposit and withdraw methods specified by
// the Account interface.

package rmi.bank;

import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class AccountImpl


extends UnicastRemoteObject
implements Account {

// The current balance of the account


private float balance = 0;

// Create a new account implementation with a new


account balance
public AccountImpl (float newBalance)
throws RemoteException {
balance = newBalance;
}

Rappels: RMI 7/141


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

réalisation de l’interface Account — AccountImpl (suite)


// Methods implemented from Account

// Return the current account balance


public float getBalance () throws RemoteException {
return balance;
}

// Deposit money into the account,


// as long as it is a positive number
public void deposit (float money)
throws BadMoneyException, RemoteException {
// Is the deposit amount a negative number?
if (money < 0) {
throw new BadMoneyException
("Attempt to deposit negative money!");
} else {
balance += money;
}
}

// Withdraw money from the account, up to the


// value of the current account balance
public void withdraw (float money)
throws BadMoneyException, RemoteException {
// Is the deposit amount a negative number?
if (money < 0) {
throw new BadMoneyException
("Attempt to deposit negative money!");
} else {
// Is there sufficient money in the account?
if ((balance - money) < 0) {
throw new BadMoneyException
("Attempt to overdraw your account!");
} else {
balance -= money;
}
}
}
}

Rappels: RMI 7/142


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

AccountManagerImpl
La classe AccountManagerImpl est chargée de créer et d’enregistrer de
nouveaux comptes (sous forme d’objets AccountImpl). Cette classe
utilise un vecteur (Vector) permettant d’enregistrer les objets Account
dans une classe de conteneurs appelée AccountInfo, associée au nom
du compte String. Cette classe utilitaire facilite la recherche d’un objet
Account existant.
// AccountManagerImpl - Implementation of the
AccountManager
// interface
//
// This version of the AccountManager class stores all
// instances of the Account(s) it creates in a Vector
// object - if an account requested exists, it will
// return that account.

package rmi.bank;

import java.util.Vector;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;

public class AccountManagerImpl


extends UnicastRemoteObject
implements AccountManager {

// Local storage of account names


private static Vector accounts = new Vector ();

// This empty constructor is required to create an


// instance of this class in the server
public AccountManagerImpl () throws RemoteException
{
}

Rappels: RMI 7/143


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

AccountManagerImpl (suite)
// Implement method from AccountManager interface
// Create an instance of an Account - if the account
// name already exists, return that account instead
// of creating a new one
public Account open (String name, float
initialBalance)
throws BadMoneyException, RemoteException {
AccountInfo a;
// Check if this name is in the list already
for (int i = 0; i < accounts.size(); i++) {
a = (AccountInfo)accounts.elementAt(i);
if (a.name.equals (name)) {
return (a.account);
}
}
// Check the initial account value...
if (initialBalance < 0) {
throw new BadMoneyException ("Negative initial
balance!");
}
// Store the new account
a = new AccountInfo();
// Try to create a new account with the starting
balance
try {
a.account = new AccountImpl (initialBalance);
} catch (RemoteException e) {
System.err.println ("Error opening account: "
+ e.getMessage());
throw (e);
}
a.name = name;
accounts.addElement (a);
// Return and instance of an AccountImpl object
return (a.account);
}
}

Rappels: RMI 7/144


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

AccountManagerImpl

Classe de conteneurs

La classe de conteneurs AccountInfo est utilisée par la classe


AccountManagerImpl.
// A container class for instance of Accounts
// that is stored in the Vector object

class AccountInfo {
String name;
AccountImpl account = null;
}

Rappels: RMI 7/145


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Compilation du code
Le chemin d’accès aux classes est important pour la réussite de l’exécution
du code RMI. Il est recommandé d’envisager l’utilisation de l’option -d
du compilateur pour localiser les fichiers de classes créés :
% javac -d classDirectory *.java

Dans l’exemple de code ci-dessus, le répertoire de package rmi/bank est


créé dans le répertoire courant.

Rappels: RMI 7/146


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Utilisation de la commande rmic


Après compilation des classes de réalisation , vous devez créer les codes
stub et skeleton permettant d’accéder aux classes de réalisation. Vous
rappellerez les classes stubs utilisées par le code client pour communiquer
avec le code skeleton du serveur.

La commande rmic créera des codes stub et skeleton à partir des


définitions des interfaces et des classes de réalisation.

Cette étape doit être exécutée après compilation des classes de réalisation
et avant exécution de l’application serveur. La syntaxe de la commande
est la suivante :

rmic [options] package.interfaceImpl ...

Exemple :
% rmic -d classDirectory rmi.bank.AccountManagerImpl \
rmi.bank.AccountImpl

L’exemple suivant créera quatre classes supplémentaires dans le


répertoire rmi/bank (package) :
AccountImpl_Skel.class
AccountImpl_Stub.class
AccountManagerImpl_Skel.class
AccountManagerImpl_Stub.class

Rappels: RMI 7/147


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Application BankServer
BankServer gère l’objet AccountManagerImpl. Son unique fonction
consiste à fournir une instance AccountManager à tout client
demandeur.
// BankServer - This class is run on the RMI server
// and is responsible for registering the AccountManager
// implementation.
package rmi.bank;
import java.rmi.*;
public class BankServer {
public static void main(String args[])
{
// Create and install the security manager
System.setSecurityManager(new
RMISecurityManager());
try {
// Create the object instance for registration
System.out.println
("BankServer.main: creating an
AccountManagerImpl");
AccountManagerImpl acm = new AccountManagerImpl
();
// Bind the object instance to the registry
System.out.println
("BankServer.main: bind it to a name:
bankManager");
Naming.rebind("bankManager", acm);
System.out.println("bankManager Server
ready.");
} catch (Exception e) {
System.out.println
("BankServer.main: an exception occurred: " +
e.getMessage());
e.printStackTrace();
}
}
}

Rappels: RMI 7/148


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Application BankServer (suite)


Le serveur “publie” l’instance de l’objet AccountManagerImpl en
associant cet objet à un nom stocké dans une application “d’aiguillage”
rmiregistry.

L’affectation s’effectue à la ligne 23 du programme précédent


Naming.rebind("bankManager", acm);

par le biais de la méthode rebind de la classe java.rmi.Naming. Cette


méthode associe ou “affecte” le nom bankManager à l’objet acm, en
supprimant tout objet précédemment affecté à ce nom dans le Registre.

La classe Naming fournit deux méthodes permettant au développeur


d’enregistrer une réalisation, bind et rebind, la seule différence résidant
dans le fait que la méthode bind générera une exception
java.rmi.AlreadyBoundException si un autre objet a déjà été
enregistré sur ce serveur, à l’aide du nom transmis à la méthode en tant
que premier argument.

Les arguments d’affectation et de réaffectation se présentent sous forme


de chaîne de type URL contenant le nom d’instance de réalisation d’objet.
La chaîne URL doit respecter le format
rmi://host:port/name

où rmi désigne le protocole, host est le nom du serveur RMI (qui devrait
être compatible DNS ou NIS+), port est le numéro de port que le serveur
doit écouter pour les requêtes, et name est le nom exact que les clients
doivent utiliser dans les requêtes Naming.lookup pour cet objet.

Les valeurs par défaut sont rmi pour le protocole, l’hôte local pour host
1099 pour port.

Rappels: RMI 7/149


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Application rmiregistry
rmiregistry est une application fournissant un simple service
d’aiguillage sur un nom. L’application BankServer fournit à
l’application rmiregistry la référence d’objet et un nom string par le
biais de l’appel de méthode rebind.

L’application rmiregistry doit être exécutée avant que l’application


BankServer ne tente l’affectation :
% rmiregistry &
% java rmi.bank.BankServer &

Les propriétés peuvent être définies pour la machine JVM du serveur RMI
dans la ligne de commande :

• java.rmi.server.codebase – Cet URL indique l’emplacement


où les clients peuvent télécharger les classes.

• java.rmi.server.logCalls – Si la valeur retournée est “vraie”,


le serveur consigne les appels dans stderr. La valeur par défaut
est “faux”.
% java -Djava.rmi.server.logCalls=true rmi.bank.BankServer &

Après exportation de la réalisation par le Registre, le client peut expédier


une chaîne URL pour demander à ce que l’application rmiregistry
fournisse une référence de l’objet distant. La recherche s’effectue par le
biais d’un appel client de Naming.lookup, en transmettant une chaîne
URL sous forme d’argument :
rmi://host:port/name

La page suivante présente la recherche utilisée par l’application client.

Rappels: RMI 7/150


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Application BankClient
L’application BankClient tente de localiser un objet AccountManager
en effectuant une recherche à l’aide d’un aiguilleur (Registry). Cet
aiguilleur se situe dans host:port dans la chaîne URL transmise à la
méthode Naming.lookup(). L’objet retourné est “vu” (converti par cast)
comme un gestionnaire de compte (AccountManager) et peut servir à
ouvrir un compte avec un nom et à lancer le calcul du solde.
// BankClient - the test program for the Bank RMI example
//
// This class simply attempts to locate the "bankManager"
// RMI object reference, then binds to it and opens an
// instance to an AccountManager implementation at the
// <server> location.
//
// Then it requests an Account with <name> and
optionally,
// an initial balance (for a new account).
//
// The class then tests the account by depositing and
// withdrawing money and looking at the account balance.
package rmi.bank;
import java.rmi.*;
public class BankClient {
public static void main(String args[])
{
// Check the argument count
if (args.length < 2) {
System.err.println ("Usage:");
System.err.println
("java BankClient <server> <account name>
[initial balance]");
System.exit (1);
}
// Create and install the security manager
System.setSecurityManager(new
RMISecurityManager());

Rappels: RMI 7/151


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Application BankClient (suite)


try {
// Get the bank instance
System.out.println ("BankClient: lookup
bankManager");
String url = new String
("rmi://"+args[0]+"/bankManager");
AccountManager acm =
(AccountManager)Naming.lookup(url);
// Set the account balance, if passed as an
argument
float startBalance = 0.0f;
if (args.length == 3) {
Float F = Float.valueOf(args[2]);
startBalance = F.floatValue();
}
// Get an account (either new or existing)
Account account = acm.open (args[1],
startBalance);
// Now do some stuff with the remote object
implementation
System.out.println ("BankClient: current balance
is: " +
account.getBalance ());
System.out.println ("BankClient: withdraw
50.00");
account.withdraw (50.00f);
System.out.println ("BankClient: current balance
is: " +
account.getBalance ());
System.out.println ("BankClient: deposit
100.00");
account.deposit (100.00f);
System.out.println ("BankClient: current balance
is: " +
account.getBalance ());
System.out.println ("BankClient: deposit 25.00");
account.deposit (25.00f);
System.out.println ("BankClient: current balance
is: " +
account.getBalance ());

Rappels: RMI 7/152


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
} catch (Exception e) {
System.err.println("BankClient: an exception
occurred: " +
e.getMessage());
e.printStackTrace();
}
System.exit(1);
}
}

Rappels: RMI 7/153


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Application BankClient (suite)


Après avoir ouvert un compte, l’application BankClient exécute les
opérations simples de dépôt et de retrait. Cette classe pourrait (et devrait
probablement) posséder une interface interactive qui permettrait au client
de saisir le nom du compte, puis d’effectuer un retrait ou un dépôt.

Exécution de l’application BankClient


L’application BankClient peut être exécutée à partir de tout hôte
autorisé à accéder au Registre et au package contenant les fichiers de
classes de l’application client, des stubs et des interfaces.

Rappels: RMI 7/154


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Création d’une application RMI

Exécution de l’application BankClient

Syntaxe

java rmi.bank.BankClient hostname accountName initialBalance

Exemples

% java rmi.bank.BankClient mach1 fred 1000


BankClient: lookup bankManager
BankClient: current balance is: 1000.0
BankClient: withdraw 50.00
BankClient: current balance is: 950.0
BankClient: deposit 100.00
BankClient: current balance is: 1050.0
BankClient: deposit 25.00
BankClient: current balance is: 1075.0

Il est à noter que l’objet distant AccountManagerImpl situé sur le


serveur, enregistre l’instance du compte créé avec le nom fred. Par
conséquent, la réexécution de l’application BankClient avec le même
nom de compte utilisera le même objet :
% java rmi.bank.BankClient mach1 fred
BankClient: lookup bankManager
BankClient: current balance is: 1075.0
BankClient: withdraw 50.00
BankClient: current balance is: 1025.0
BankClient: deposit 100.00
BankClient: current balance is: 1125.0
BankClient: deposit 25.00
BankClient: current balance is: 1150.0

Rappels: RMI 7/155


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Sécurité RMI

Chargement de classe
Pour utiliser RMIClassLoader, un gestionnaire de sécurité doit déjà
exister afin de s’assurer que les classes chargées à partir du réseau
satisfont aux critères standard de sécurité Java. Si aucun gestionnaire n’est
en place, l’application ne peut pas charger les classes à partir d’hôtes
distants.

Côté serveur RMI

Lors de l’envoi de la commande java permettant d’appeler la machine


JVM côté serveur, il est possible de définir deux propriétés (dont l’une des
deux a été précédemment évoquée dans ce module) pour déterminer
l’emplacement des classes RMI :

• java.rmi.server.codebase – Cet URL indique l’emplacement à


partir duquel les clients peuvent télécharger les classes et indique
que le serveur peut, si nécessaire, charger des classes à partir des
URL du client.

• java.rmi.server.useCodebaseOnly – Si la valeur retournée est


“vrai”, le chargement de classes à partir des URL du client est
désactivé.

Rappels: RMI 7/156


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7
Sécurité RMI

Chargement de classe

Côté client RMI

Si le programme client RMI est une applet, son gestionnaire de sécurité


(SecurityManager) et son chargeur de classe (ClassLoader) sont
mandatés par le browser côté client.

Cependant, si le programme client est une application, les seules classes


qui seraient téléchargées à partir du serveur RMI seraient les définitions
d’interfaces distantes, les classes stubs , les classes d’arguments étendues
et les valeurs retournées par les appels de méthodes distants. Si une
application client tente de charger des classes supplémentaires à partir du
serveur, elle peut utiliser RMIClassLoader.loadClass, en fournissant
comme paramètres les mêmes URL et identificateur que ceux transmis
dans Naming.lookup.

Invocation RMI au travers d’un coupe-feu


La couche transport RMI tente normalement d’ouvrir des sockets directs
des clients aux serveurs. Néanmoins, s’il est impossible d’établir une
connexion directe au serveur par socket , la méthode createSocket de
la classe java.rmi.server.RMISocketFactory retentera la requête
sous forme de connexion par protocole de tranfert hypertexte (HTTP) en
expédiant l’appel RMI sous forme de requête HTTP POST.

Si la méthode createServerSocket détecte que la connexion


récemment acceptée est une requête HTTP POST, les informations
retournées seront réexpédiées dans le corps d’une réponse HTTP.

Aucune configuration spéciale n’est requise pour permettre au client


d’effectuer des appels RMI au travers d’un coupe-feu.

Rappels: RMI 7/157


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
7

Rappels: RMI 7/158


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
Méthodes natives avec JNI 8

Objectifs
Ce chapitre introduit l’API Java Native Interface qui permet d’étendre
JAVA avec du code compilé écrit en C ou C++:

• Pourquoi réaliser du code natif?

• Les phases de génération : un exemple simple

• Les caractéristiques générales de JNI

• Exemples : emploi des types Java en C, accès aux attributs des


objets JAVA, création d’instances.

• Le problème de l’intégrité des références aux objets JAVA.

• Le traitement des exceptions JAVA

• L’invocation de JAVA à l’intérieur d’un code C/C++.

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
Pourquoi réaliser du code natif?

Il y a des situations dans laquelle le code ne peut pas être complétement


écrit en JAVA :

• Une grande quantité de code compilé existe déja et fonctionne


de manière satisfaisante. La fourniture d’une interface avec
JAVA peut être plus intéressante qu’une réécriture complète.

• Une application doit utiliser des services non fournis par JAVA
(et en particulier pour exploiter des spécificités de la plate-
forme d’exécution. Exemple : accès à des cartes).

• Le système JAVA n’est pas assez rapide pour des applications


critiques et la réalisation dans un code natif serait plus
efficiente.

Il est possible d’implanter en JAVA des méthodes natives réalisées


typiquement en C ou C++.

Une classe comprenant des méthodes natives ne peut pas être téléchargée
au travers du réseau de manière standard: il faudrait que le serveur ait
connaissance des spécificités de la plate-forme du client. De plus une telle
classe ne peut faire appel aux services de sécurité de JAVA (en 1.1)

Bien entendu pour toute application JAVA qui s’appuie sur des
composants natifs on doit réaliser un portage du code natif sur chaque
plate-forme spécifique. De plus c’est un code potentiellement plus fragile
puisque les contrôles (pointeurs, taille, etc.) et la récupération d’erreurs
sont entièrement sous la responsabilité du programmeur.

Il existe diverses manières d’assurer cette liaison code compilé-Java.


Depuis la version JAVA 1.1 le protocole JNI a été défini pour rendre cette
adaptation plus facilement indépendante de la réalisation de la machine
virtuelle sous-jacente.

D’autre part il est également possible d’exécuter du code JAVA au sein


d’une application écrite en C/C++ en appelant directement la machine
virtuelle ( JAVA "enchassé" dans C).

Méthodes natives avec JNI 8/160


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
un exemple : "Hello World" en C

résumé des phases :

Ecriture du code JAVA :

• Création d’une classe "HelloWorld" qui déclare une méthode


(statique) native.

Création des binaires JAVA de référence :

• Compilation du code ci-dessus par javac .

Génération du fichier d’inclusion C/C++ :

• Ce fichier est généré par l’utilitaire javah . Il fournit une


définition d’un en-tête de fonction C pour la réalisation de la
méthode native getGreetings() définie dans la classe Java
"HelloWorld".

Ecriture du code natif :

• Ecriture d’un fichier source C (".c") qui réalise en C le code de


la méthode native. Ce code fait appel à des fonctions et des
types prédéfinis de JNI.

Création d’une librairie dynamique:

• Utilisation du compilateur C pour générer une librairie


dynamique à partir des fichiers .c et .h définis ci-dessus. (sous
Windows une librairie dynamique est une DLL)

Exécution:

• Exécution du binaire JAVA (par java) avec chargement


dynamique de la librairie.

Méthodes natives avec JNI 8/161


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
un exemple : "Hello World" en C

Ecriture du code JAVA


Le code de l’exemple définit une classe JAVA nommée "HelloWorld" et
faisant partie du package "hi".
package hi ;

class HelloWorld {

static {
System.loadLibrary("hello");
}
public static native String getGreetings();

public static void main (String[] tArgs) {


for (int ix = 0 ; ix < tArgs.length; ix++) {
System.out.println(getGreetings() + tArgs[ix]) ;
}
}// main
}

Cette classe pourrait contenir également d’autres définitions plus


classiques (champs, méthodes, etc.). On remarquera ici :

• La présence d’un bloc de code static exécuté au moment du


chargement de la classe. A ce moment il provoque alors le
chargement d’une bibliothèque dynamique contenant le code
exécutable natif lié à la classe.
Le système utilise un moyen standard (mais spécifique à la
plate-forme) pour faire correspondre le nom "hello" à un nom
de bibliothèque ( "libhello.so" sur Solaris, "hello.dll" sur
Windows,...)

• La définition d’un en-tête de méthode native.


Une méthode marquée native ne dispose pas de corps.
Comme pour une méthode abstract le reste de la "signature"
de la méthode (arguments, résultat,...) doit être spécifié.
(ici la méthode est static mais on peut, bien sûr, créer des
méthodes d’instance qui soient natives).

Méthodes natives avec JNI 8/162


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
un exemple : "Hello World" en C

Création des binaires JAVA de référence


La classe ainsi définie se compile comme une autre classe :
javac -d . HelloWorld.java

(autre exemple sous UNIX : au lieu de "-d ." on peut faire par exemple "-
d $PROJECT/javaclasses")

Le binaire JAVA généré est exploité par les autres utilitaires employés
dans la suite de ce processus.

Dans l’exemple on aura un fichier "HelloWorld.class" situé dans le sous-


répertoire "hi" du répertoire ciblé par l’option "-d"

Méthodes natives avec JNI 8/163


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
un exemple : "Hello World" en C

Génération du fichier d’inclusion C/C++


L’utilitaire javah va permettre de générer à partir du binaire JAVA un
fichier d’inclusion C/C++ ".h". Ce fichier définit les prototypes des
fonctions qui permettront de réaliser les méthodes natives de HelloWorld.
javah -d . -jni hi.HelloWorld

(autre exemple sous UNIX: javah -d $PROJECT/csources ....)


On obtient ainsi un fichier nommé hi_HelloWorld.h :
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class hi_HelloWorld */

#ifndef _Included_hi_HelloWorld
#define _Included_hi_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: hi_HelloWorld
* Method: getGreetings
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_hi_HelloWorld_getGreetings
(JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

Des règles particulières régissent la génération du nom de fichier


d’inclusion et des noms de fonctions réalisant des méthodes natives.
On notera que la fonction rend l’équivallent d’un type JAVA (jstring) et,
bien qu’étant définie sans paramètres en JAVA, comporte deux paramètres
en C. Le pointeur d’interface JNIEnv permet d’accéder aux objets JAVA,
jclass référence la classe courante (on est ici dans une méthode statique:
dans une méthode d’instance le paramètre de type jobject référencerait
l’instance courante).

Méthodes natives avec JNI 8/164


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
un exemple : "Hello World" en C

Ecriture du code natif


En reprenant les prototypes définis dans le fichier d’inclusion on peut
définir un fichier source C : "hi_HelloWorldImp.c" :
#include <jni.h>
#include "hi_HelloWorld.h"

/*
* Class: hi_HelloWorld
* Method: getGreetings
* Signature: ()Ljava/lang/String;
* on a une methode statique et c’est la classe
* qui est passée en paramètre
*/
JNIEXPORT jstring JNICALL Java_hi_HelloWorld_getGreetings
(JNIEnv * env , jclass curclass) {

return (*env)->NewStringUTF(env, "Hello ");


}

env nous fournit une fonction NewStringUTF qui nous permet de


générer une chaîne JAVA à partir d’une chaîne C.

NOTA : en C++ les fonctions JNI sont "inline" et le code s’écrirait :


JNIEXPORT jstring JNICALL Java_hi_HelloWorld_getGreetings
(JNIEnv * env , jclass curclass) {

return env->NewStringUTF("Hello ");


}

Méthodes natives avec JNI 8/165


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
un exemple : "Hello World" en C

Création d’une librairie dynamique


Exemple de génération sous UNIX (le ".h" est dans le répertoire courant)
#!/bin/sh
# changer DIR en fonction des besoins
DIR=/usr/local/java
cc -G -I$DIR/include -I$DIR/include/solaris \
hi_HelloWorldImp.c -o libhello.so

Exemple de génération sous Windows avec le compilateur VisualC++4.0:

cl -Ic:\java\include -Ic:\java\include\win32 -LD


hi_HelloWorldImp.c -Fehello.dll

Méthodes natives avec JNI 8/166


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
un exemple : "Hello World" en C

Exécution

java hi.HelloWorld World underWorld


Hello World
Hello underWorld

Si, par contre, vous obtenez une exception ou un message indiquant que
le système n’a pas pu charger la librairie dynamique il faut positionner
correctement les chemins d’accès aux librairies dynamiques
(LD_LIBRARY_PATH sous UNIX)

Méthodes natives avec JNI 8/167


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
présentation de JNI

JNI est une API de programmation apparue à partir de la version 1.1 de


JAVA. Il existait auparavant d’autres manières de réaliser des méthodes
natives. Bien que ces autres APIs soient toujours accessibles elles
présentent quelques inconvénients en particulier parce qu’elles accèdent
aux champs des classes JAVA comme des membres de strcutures C (ce
qui oblige à recompiler le code quand on change de machine virtuelle) ou
parcequ’elles posent quelques problèmes aux glaneurs de mémoire
(garbage collector).

Les fonctions de JNI sont adressables au travers d’un environnement


(pointeur d’interface vers un tableau de fonctions) spécifique à un thread.
C’est la machine virtuelle elle même qui passe la réalisation concrète de ce
tableau de fonctions et on assure ainsi la compatibilité binaire des codes
natifs quel que soit la machine virtuelle effective.

Les fonctions proposées permettent en particulier de :

• Créer, consulter, mettre à jour des objets JAVA, (et opérer sur leurs
verrous). Opérer avec des types natifs JAVA.

• Appeler des méthodes JAVA

• Manipuler des exceptions

• Charger des classes et inspecter leur contenu

Le point le plus délicat dans ce partage de données entre C et JAVA et


celui du glaneur de mémoire (garbage collector): il faut se protéger contre
des déréférencements d’objets ou contre des effets de compactage en
mémoire (déplacements d’adresses provoqués par gc), mais il faut savoir
aussi faciliter le travail du glaneur pour recupérer de la mémoire.

Méthodes natives avec JNI 8/168


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
JNI: types, accès aux membres, création d’objets

Soit l’exemple de classe :


package hi ;
class Uni {
static {
System.loadLibrary("uni");
}
public String [] tb ;// champ "tb"
public Uni(String[] arg) {
tb = arg ;
}// constructeur
public native String [] getMess(int n, String mess);
public static native Uni dup(Uni other);

public String toString() {


String res = super.toString() ;
// pas efficient
for (int ix = 0 ; ix < tb.length; ix ++) {
res = res + ’\n’ + tb[ix] ;
}
return res ;
}
public static void main (String[] tArgs) {
Uni you = new Uni(tArgs) ;
System.out.println(you) ;
String[] mess = you.getMess(tArgs.length,
" Hello") ;
for (int ix = 0 ; ix < mess.length; ix++) {
System.out.println(mess[ix]) ;
}
Uni me = Uni.dup(you) ;
System.out.println(me) ;
}// main
}

Exemple d’utilisation :
java hi.Uni World
hi.Uni@1dce0764
World
Hello
hi.Uni@1dce077f
World

Méthodes natives avec JNI 8/169


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
JNI: types, accès aux membres, création d’objets

La méthode native getMess(int nb, String mess) génère un


tableau de chaînes contenant "nb" fois le même message "mess" :
/* Class: hi_Uni
* Method: getMess
* Signature: (ILjava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL
Java_hi_Uni_getMess (JNIEnv * env , jobject curInstance,
jint nb , jstring chaine) {
/* quelle est la classe de String ? */
jclass stringClass = (*env)->FindClass(env,
"java/lang/String") ;
/* un tableau de "nb" objet de type "stringClass"
* chaque element est initialise a "chaine" */
return (*env)->NewObjectArray(env,
(jsize)nb,stringClass,chaine) ;
}

• La fonction NewObjectArray est une des fonctions de création


d’objets JAVA. Elle doit connaître le type de ses composants (ici
fourni par "stringClass").
L’initialisation de chaque membre d’un tel tableau se fait par
l’accesseur SetObjectArrayElement() - mais ici on profite du
paramètre d’initialisation par défaut-

• JNI fournit des types C prédéfinis pour représenter des types


primitifs JAVA (jint) ou pour des types objets (jobject,
jstring,..)

• La fonction FindClass permet d’initialiser le bon paramètre


désignant la classe "java.lang.String" (la notation utilise le
séparateur "/"!).
Noter également la représentation de la signature de la fonction
"getMess": (ILjava/lang/String;) indique un premier paramètre
de type int (symbolisé par la lettre I) suivi d’un objet (lettre L+ type + ; ) .
De même [Ljava/lang/String; désigne un résultat qui est un
tableau à une dimension (lettre [) contenant des chaînes.

Méthodes natives avec JNI 8/170


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
JNI: types, accès aux membres, création d’objets

La méthode statique "dup" clone l’instance passée en paramètre :


/* Class: hi_Uni; Method: dup
* Signature: (Lhi/Uni;)Lhi/Uni; */
JNIEXPORT jobject JNICALL Java_hi_Uni_dup (JNIEnv * env,
jclass curClass , jobject other) {
jfieldID idTb ; jobjectArray tb ;
jmethodID idConstr ;
/* en fait inutile puisque c’est curClass !*/
jclass uniClass = (*env)->GetObjectClass(env, other) ;
if(! (idTb = (*env)->GetFieldID (env,uniClass,
"tb","[Ljava/lang/String;")))
return NULL ;
tb = (jobjectArray) (*env)->GetObjectField(env,
other,idTb) ;

/* on initialise un nouvel objet */


if(!(idConstr = (*env)->GetMethodID(env, curClass,
"<init>", "([Ljava/lang/String;)V")))
return NULL ;
return (*env)->NewObject(env,
curClass,idConstr,tb) ;
}

• La récupération du champ "tb" (de type tableau de chaîne) sur


l’instance passée en paramètre se fait par la fonction
GetObjectField. On a besoin de la classe de l’instance consultée
et de l’identificateur du champ qui est calculé par GetFieldID.

• De la même manière l’appel d’une méthode nécessite une classe et


un identificateur de méthode calculé par GetMethodID.
Ici ce n’est pas une méthode qui est appelée mais un constructeur
et l’identifiant est calculé de manière particulière ("<init>"), le type
indique un paramètre de type tableau de chaîne et un "résultat"
qui est void (lettre V ) .

JNI fournit ainsi des accesseurs à des champs


(Get<static><type>Field, Set<static><type>Field) et des
moyens d’appeler des méthodes (Call<statut><type>Method :
exemple CallStaticBooleanMethod). Il existe, en plus, des méthodes
spécifiques aux tableaux et aux Strings

Méthodes natives avec JNI 8/171


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
références sur des objets JAVA:

Le passage du glaneur de mémoire sur des objets JAVA pourrait avoir


pour effet de rendre leur référence invalide ou de les déplacer en
mémoire. Les reférences d’objet JAVA transmises dans les transitions vers
le code natif sont protégées contre les invalidations (elles redeviennent
récupérables à la sortie du code natif).

Toutefois JNI autorise le programmeur à explicitement rendre une


référence locale récupérable. Inversement il peut aussi se livrer à des
opérations de "punaisage" (pinning) lorsque, pour des raisons de
performances, il veut pouvoir accéder directement à une zone mémoire
protégée :
const char * str = (*env)->GetStringUTFChars(env,
javaString,0) ;
.... /* opérations sur "str" */
(*env)->ReleaseStringUTFChars(env, javaString, str) ;

Des techniques analogues existent pour les tableaux de scalaires primitifs


(int, float, etc.). Bien entendu il est essentiel que le programmeur C libère
ensuite la mémoire ainsi gelée.
Si on veut éviter de bloquer entièrement un tableau alors qu’on veut
opérer sur une portion de ce tableau , on peut utiliser des fonctions
comme :
void GetIntArrayRegion(JNIenv* env, jintArray tableau,
jsize debut, jsize taille, jint * buffer) ;
void SetIntArrayRegion(....

Le programmeur a aussi la possibilité de créer des reférences globales sur


des objets JAVA. De telles références ne sont pas récupérables par le
glaneur à la sortie du code natif, elles peuvent être utilisées par plusieurs
fonctions implantant des méthodes natives. Ici aussi il est de la
responsabilité du programmeur de libérer ces références globales.

Méthodes natives avec JNI 8/172


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
exceptions

JNI permet de déclencher une exception quelconque ou de recupérer une


exception JAVA provoquée par un appel à une fonction JNI. Une
exception JAVA non récupérée par le code natif sera retransmise à la
machine virtuelle .
....
jthrowable exc;
(*env)->CallVoidMethod(env, instance , methodID) ;
/* quelque chose s’est-il produit? */
exc = (*env)->ExceptionOccurred(env);
if (exc) {
jclass NouvelleException ;
... /* diagnostic */
/* on fait le ménage */
(*env)->ExceptionClear(env) ;
/* et on fait du neuf ! */
NouvelleException = (*env)->FindClass(env,
"java/lang/IllegalArgumentException") ;
(*env)->ThrowNew(env,NouvelleException, message);
}
...

Méthodes natives avec JNI 8/173


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
8
invocation de JAVA dans du C

/*lanceur.c
* usage : lanceur <classe_JAVA_en_format_/> <args> */
JavaVM *jvm ;
JNIEnv * env;
JDK1_1InitArgs vm_args ; /* 1.2 : JavaVMInitArgs */

main(argc, argv) int argc; char ** argv; {


int cnt ; jint res ; jclass mainclass ;
jmethodID methodID; jobjectArray jargs ;
/* ici controles de lancement a faire */
....
/* initialisation des champs de vm_args ATTENTION*/
vm_args.version = 0x00010001 ; /* CHANGE en 1.2 ! */
/* appel obsolete en JAVA 1.2 */
res = JNI_GetDefaultJavaVMInitArgs(&vm_args) ;
/* APPEL OBSOLETE (non portable). CHANGE en 1.2 */
vm_args.classpath = getenv("CLASSPATH");
if (0> JNI_CreateJavaVM(&jvm, &env, &vm_args))exit(1) ;

if (!(mainclass= (*env)->FindClass(env,argv[1])))
exit(1);
if(!(methodID= (*env)->GetStaticMethodID(env,mainclass,
"main","([Ljava/lang/String;)V")))exit(2);
....
jargs = (*env)->NewObjectArray(env,(jsize)(argc-2),
(*env)->FindClass(env,"java/lang/String"), NULL) ;
for (cnt = 0 ; cnt < (argc - 2) ; cnt++) {
jobject stringObj = (*env)->NewStringUTF(env,
argv[cnt+2]);
(*env)->SetObjectArrayElement(env,
jargs,(jsize)cnt,stringObj);
}
(*env)->CallStaticVoidMethod(env,
mainclass, methodID, jargs) ;
.....
(*jvm)->DestroyJavaVM(jvm) ;
}

Un tel code doit être lié à la librairie binaire JAVA (libjava.so sous
UNIX).
La version de JAVA 1.2 introduit quelques modifications (voir
documentation).

Méthodes natives avec JNI 8/174


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
Recommandations de programmation 9

Objectifs
Dans ce document nous avons rassemblé quelques considérations sur la
manière de coder en JAVA.

Ces remarques sont faites pour guider vos recherches plutôt que pour
édicter des règles intangibles. JAVA étant un langage neuf l’essentiel des
savoir-faires est encore en gestation.

• organisation en "packages"

• conventions de codage

• portabilité

• performances

• traces, exceptions

• Le "bon" et le "beau" code

• les interactions graphiques

• la répartition

• l’internationalisation

• l’intégration de code natif

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
Organisation des packages et des répertoires

• Ne pas développer de classe sans qu’elle soit rattachée à un


package. Un package regroupera un ensemble de classes reliées
par des objectifs communs.
L’instruction "package XXXX ;" doit être la première d’un
fichier ".java".

• Le package permet de créer un espace de nommage. Par exemple


ont peut utiliser plusieurs classes "Rectangle" tant que chacune
existe dans un package différent (et que l’on sait lever les
ambiguités en les désignant dans le code).
Il est recommandé de préfixer tous les packages d’une socitété ou
organisation par l’identification Internet de cette organisation.
Exemple: soit la société ACME (adresse "acme.com"); alors un
package pourra se déclarer comme :
package com.acme.finance.swap ;

• Bien que ça ne soit pas strictement obligatoire il est vivement


conseillé de faire correspondre une hiérarchie de répertoires à la
hiérarchie de packages. Exemple (sous Unix) :
package projet1.package1; // dans Fichier.java
javac projet1/package1/Fichier.java
java projet1.package1.Fichier
<APPLET code="projet1.package1.Applet2.class"...

• Autre idée d’organisation utile : séparer soigneusement la


hiérarchies des répertoires contenant les sources ".java" des
hiérarchies contenant les fichiers ".class"

• avantages : permet de disposer de plusieurs types de fichiers


".class" (avec debug, optimisé, avec ou sans traces, etc.), permet
de développer et tester des modifications pendant que les
autres développeurs utilisent l’ancienne version des classes,
etc.

• inconvénients : demande une bonne maîtrise des CLASSPATH


et du comportement du compilateur (en particulier au niveau
de la recherche de mise à jour des classes dépendantes)

• ATTENTION : Au sein d’une application le ClassLoader peut être


amené à charger autre choses que des ".class" (par ex. des fichiers
de ressources -images, properties,etc.-) Ces ressources font partie
des hiérarchies de package et il faut s’organiser en conséquence.

Recommandations de programmation 9/176


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
convention de codage

références :

De nombreux sites (on constatera qu’il n’y a pas unanimité sur les règles à
suivre!), voir par ex:
http://g.oswego.edu/dl/html/javaCodingStd.html

Identificateurs (conventions standard)


• Classes et interfaces : MaClasse, MonInterface

• Constantes de Classe : MAX, MAX_SIZE

• Variables, méthodes : maVariable, maMethode()

Identificateurs (conseils complémentaires)


• Eviter les caractères "_" et "$" au milieu des identificateurs (risques
de confusion avec des identifiants générés pour les classes internes
ou les méthodes natives)

• Certaines conventions de nommage sont standard :

• Conventions "Beans" (obligatoires pour permttre


l’instrospection) : Accesseurs (propriétés), Propriétés
booléennes, Propriétés indexées, méthodes sur événements,..
// Accesseur simple
public PropertyType getPropertyName()
public void setPropertyName(PropertyType x)

• Conventions RMI :
public class AccountImpl extends
UnicastRemoteObject
implements Account {

• Conventions spécifiques aux méthodes natives

Recommandations de programmation 9/177


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
convention de codage (suite)

Nommage (conseils complémentaires)


• Eviter les excès bureaucratiques : il est souhaitable que chaque
nom soit facilement lisible et que l’on comprenne l’intention
sémantique qui lui est associé, par contre un excès de règles
formalisées n’est pas forcément un plus!
Exemple: obliger les programmeurs à mettre dans le nom une
indication qui rappelle de type de l’objet est plutot génant -
surtout si ce type est amené à changer au cours du
développement-.

• Nommage des Exceptions :


ToutVaMalException ;

• L’emploi de variables nommées "i", "j", "x", "p" etc. n’améliore pas
la lisibilité. De plus avec la plupart des éditeurs la recherche des
endroit où ces variables sont employées peut s’avérer difficile!
(préférer alors "iy", "ix", etc.)

Recommandations de programmation 9/178


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
convention de codage (suite)

Mise en page
• Mettre en place des règles cohérentes de mise en page :
// alignements des accolades
public void maMethode(int arg) {
//indentations internes correctes
...
}//End maMethode

if ( cestVrai ) {
// on met les accolades
// même pour une seule instruction
}

• Rendre lisibles les sources : limiter le nombre de caractères par


ligne (et fixer des règles de continuation sur la ligne suivante),
penser à des règles de présentation des commentaires, etc. Penser
à écrire des squelettes standard de fichiers pour Classes, Applets,
etc. de nombreux éditeurs savent utiliser de tels modèles.

• Attention : certains éditeurs (Emacs par ex.) font de l’analyse du


code non par analyse syntaxique mais par "pattern-matching", le
non-respect de certains règles peut perturber la mise en page
automatique du code.

• Pour harmoniser la description de types (voir remarque ci-dessus)


préférer la notation :
String[] args
à
String args[] ; // pour les nostalgiques du C!

• Autre rappel aux nostalgiques du langage C : il n’est pas


nécessaire de concentrer toutes les déclarations de variables locales
en début de bloc. On peut déclarer la variable le plus près possible
de l’endroit où on l’utilise -décision à prendre en fonction de
critères de maintenabilité-.

Recommandations de programmation 9/179


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
portabilité

références :

http://java.sun.com/100percent/

"Write once, run everywhere" tel est le slogan de JAVA. Si la portabilité est
un des points forts de JAVA elle n’est pas entièrement automatique: il est
parfaitement possible d’écrire des programmes non-portables!

On trouvera en fin de ce support une copie d’un document en Anglais


décrivant les principales précautions à prendre pour éviter d’écrire du
code non-portable.

Plus important encore: un Label "100%" JAVA peut être accordé aux
produits que vous développez.

Une autre difficulté peut surgir lorsque JAVA évolue et que les nouveaux
codes ne sont pas totalement compatibles avec les anciens. Ainsi le
passage de la version 1.0 de JAVA à la version 1.1 a donné lieu à de
nombreux problèmes d’adaptation des Applets puisque des Applets
publiées sur le WEB pouvaient être mis en oeuvre par des clients ayant
des niveaux différents de JAVA.

Le site java.sun.com publie les techniques pratiques concernant de telles


mises à jour. Même si elles donnent lieu à quelques récriminations ces
modifications sont aussi une garantie d’évolution et de recherche de
qualité! Pour ce qui est de la mise à jour des navigateurs voir JAVA
PLUGIN (module de mise à jour des JVM liées au navigateurs)

Recommandations de programmation 9/180


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
performances

références :

Ici aussi de nombreux sites parlent des optimisations JAVA. par ex:
http://www.cs.cmu.edu/~jch/java/optimization.html
ou les articles spécialisés dans "JavaWorld"

Il y a de très nombreuses "recettes" pour des optimisations de détail (de


plus ceci peut varier en fonction des compilateurs et des JVM). Quelques
constantes :

• L’opération "new" coûte cher. Penser à réutiliser directement les


objets dont vous n’avez plus besoin. Toutefois ceci peut rentrer en
contradiction avec une architecture comprenant des variables
membres qui sont "final" (il y a donc des choix à faire).

• On peut aider le glaneur de mémoire (garbage collector) en mettant


explicitement des références à null ( par exemple pour des
membres inutilisés d’un tableau).

• L’exploitation des moniteurs (synchronized,..) coûte très cher.A


utiliser avec modération (en particulier dans les classes utilitaires
de "bas niveau"). Pour des cas extrêmes de performances dans les
Threads l’utilisation de bibliothèques de Threads natifs permet
l’utilisation des architectures multi-processeurs.

• Le problème numero 1 des performances est celui de la complexité


cachée : combiner l’action des plusieurs composants de haut
niveau avec une encapsulation parfaite conduit parfois à ce que
chacun fasse plusieurs fois le même travail de son coté. La
détection de ces anomalies est particulièrement ardue si on fait
collaborer plusieurs composants pour lesquels on n’a pas accès au
code. Attention donc à l’usage indiscriminé de composants "gros
consommateurs"

• Les classiques : faire des E/S bufferisées, ne pas réécrire en JAVA


ce qui existe dans les méthodes d’API (ex. arraycopy()),
conserver certaines valeurs utiles, etc.

Recommandations de programmation 9/181


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
traces, exceptions

• Comment laisser dans les sources du code dédié aux traces sans
que ce code soit toujours compilé et inclus dans les exécutables ?
(Rappel: il n’y a pas en JAVA de préprocesseur permettant des
compilations conditionnelles)

Solution : utiliser des variables booléennes static et final (dont la


valeur est connue au moment de la compilation), le code protégé
par une condition (if) pour laquelle le compilateur se rendra
compte qu’elle est toujours fausse ne sera pas inclus dans le
binaire.
Exemple:
if( Trace.DEBUG && (Trace.traceMask > 8)) {
// code de trace
}

• La spécification des exceptions doit faire partie des spécifications


générales d’un projet. On doit, dès le départ, définir les grandes
lignes du traitement d’exception pour que les programmeurs ne
laissent pas le code correspondant dans un état mal défini (qui
n’est jamais ensuite repris!).
Quelques suggestions :

• Définir quelques classes d’exceptions de base dont toutes les


autres exceptions seront dérivées : on pourra ainsi mettre en
place, en temps utile, des mécanismes adaptés qui seront
appelés au moment du déclenchement de l’exception. Ex.
mettre en place une trace conditionnelle de la pile, etc.

• Déterminer quels appels de méthodes mettre en place au


moment de la récupération de l’exception. On pourra ensuite
mettre au point des récupérations sophistiquées.
Il est en effet dommage de se contenter d’écrire un message sur
la sortie d’erreur standard alors qu’on peut, par exemple, faire
parvenir à l’utilisateur un message simplifié pendant que l’on
envoie (par mail) un message détaillé à l’administrateur, ou à
l’équipe de maintenance.

• Pour les applications gérant des transactions critiques le


mécanisme finally doit être employé avec discernement : il
faut que toute opération de terminaison soit sans effet si elle est
sans objet (exemple: envoyer un close ne fait rien si open n’a
pas été appelé)

Recommandations de programmation 9/182


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
le "bon " et le "beau" code ?

Il est ici hors de question de définir ce qui caractérise un "bon" code, de


plus il n’y a pas encore de consensus sur ce que sont d’une part les
constructions potentiellement dangereuses et d’autre part ce qui
caractérise un code bien architecturé en terme d’évolutivité, lisibilité, etc.

Toutefois une équipe de développement JAVA se doit de tenir à jour un


registre des savoir-faires et d’en discuter la pertinence lors des revues de
code.

Quelques exemples de constructions à documenter :

• La redéfinition d’une variable d’instance dans un héritage (data-


hiding): produit en général des effets non-évidents

• Dans une surcharge de méthode la définition de deux méthodes


qui diffèrent simplement du fait de types objet situés dans la
même hiérarchie risque de produire des effets indésirables.
methode(Pere x) { .... }
methode(Fils x) {.... } ;

• Appels de méthodes dans un constructeur: à contrôler de près. En


effet on doit, dans un constructeur, se limiter à réaliser des
initialisations. Lancer des traitements peut se révéler hasardeux
car l’objet peut être dans un état incomplet (par exemple on va
appeler une méthode redéfinie dans le fils alors que l’on est dans
l’initialisation de "super").
Le problème est particulièrement délicat dans AWT où l’on peut
être tenté de tout décrire dans le constructeur d’un Frame par ex.
Il est donc de bon ton de doter ce Frame d’une méthode appelée
init(), ou go() ou autre et qui soit explicitement appelée après les
initialisations minimum du constructeur -cette méthode
contiendra l’essentiel du code qui sera en attente d’interactions-.

Recommandations de programmation 9/183


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
• Documenter particulièrement les objets qui peuvent servir de
support à une opération synchronized ou un wait. Il serait
dommage que, par inadvertance, un programmeur oublie de
synchroniser d’autres accès.
Par ailleurs veiller à mettre un wait dans une boucle retestant la
condition (on n’est pas sûr au reveil que cette condition soit
remplie). Faire attention aux inter-blocages : ne pas utiliser
suspend/resume et préferer notifyAll.

• Eviter les effets de bord par modification du contenu d’objets


passés en paramètre à une méthode. Si une méthode doit modifier
l’état d’un de ses paramètres il vaut mieux qu’il soit rendu en
résultat.
Outre le fait que ce comportement est considéré comme
théoriquement malsain, il va être génant si cette méthode connait
une réalisation via RMI.
De même documenter la non-utilisation d’un résultat de méthode :
Object inutilisé = maMethode(ix) ;

• Il est possible que l’emploi d’un == entre objets et d’un = dans un


test ne corresponde pas à l’intention du programmeur.
Dans un cas c’est souvent un obj1.equals(obj2) qui est
recherché , dans l’autre c’est un == (le compilateur va d’ailleurs le
détecter sauf si on tente d’écrire des expressions comme " if
(cond == true)" au lieu de "if (cond)" )

• Autant que possible initialiser explicitement les variables membres


class MaClasse {
Vector vect = new Vector() ;
// sinon risques en accédant vect

• Bien qu’une Applet soit un Panel son utilisation dans une


application autonome (ou dans une autre Applet) demande des
précautions très particulières. En effet de nombreux services
(getDocumentBase, getImage, etc.) dépendent de la présence de
AppletStub et AppletContext.

• Penser à l’internationalisation. En AWT ne pas baser le


comportement du programme sur une valeur “en dur” d’une
étiquette : passer par “setActionCommand(), setName(),...” pour
distinguer les noms symboliques des composants et des actions
associées de leur étiquette affichée.

Recommandations de programmation 9/184


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
le "bon " et le "beau" code ?

Quelques autres thèmes de discussion :

• Importer explicitement une classe d’un package plutôt que


d’importer avec "import pack.* ; "

• Un main de test peut accompagner chaque classe ayant une


fonction bien délimitée. Pour des points d’entrée d’application
faire une classe à part pour le main.

• Choix concernant l’encapsulation : préférer protected à


private; ne pas définir systématiquement des accesseurs quand
des membres "blank final" (constantes en attente d’initialisation)
suffiraient:
final String clef ;
// initialisée dans constructeur

• Pour les classes destinées à connaître une instanciation


dynamique faut-il systématiquement définir un constructeur sans
argument -appelable par newInstance()- doublé d’une méthode
d’initialisation des champs, ou prévoir de faire appel à la classe
Constructor? Dans le premier cas on bénéficie de contrôles au
moment de la compilation mais on ne peut pas toujours tout faire.

Un des points critiques du "beau" code : la programmation AWT. Le


débutant a souvent tendance à créer un code mal architecturé : il est
difficile de "voir" la dispositon et de la faire évoluer. Le codage demande
donc de gros efforts de discipline :

• Ne pas disperser les références à un objet graphique sur


l’ensemble du code. On crée un Container, on dispose son contenu
et ceci récursivement dans la hiérarchie des Containers. Ceci
suppose que l’on crée des blocs de code (ou des méthodes) qui
isolent chaque élément architectural de la disposition.
Ce découpage demande beaucoup de soins car il faut savoir
rapprocher les objets d’interactions des objets applicatifs : les
points critiques sont alors la définition des Listeners (utiliser
plutôt des classes internes qui ont accès aux données locales) et les
objets graphiques qui doivent avoir accès aux données locales
mais qui sont situés dans un autre zone de disposition (par ex.
dans une barre d’outils éloignée du Panel local -il faut imaginer
un échange entre ce Panel et la barre d’outils-)

Recommandations de programmation 9/185


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
Comparer les techniques employées dans ces deux exemples :
// VERSION 1

public class ButtonPanel extends Panel {


public ButtonPanel(Actor[] tAct) {
super(new FlowLayout(FlowLayout.LEFT)) ;
for (int ix = 0 ; ix < tAct.length; ix++) {
Button but = new Button(tAct[ix].message) ;
but.addActionListener(tAct[ix].act) ;
add(but) ;
}
}

//avec Actor {String message ;ActionListener act ;...}

// VERSION 2

public class ButtonPanel2 extends Panel


implements ActionListener{
Button b1, b2 ;
public ButtonPanel2 () {
super(new FlowLayout(FlowLayout.LEFT)) ;
b1 = new Button ("Hello") ;
b1.addActionListener(this) ;
b2 = new Button ("World") ;
b2.addActionListener(this) ;
add(b1) ;
add(b2) ;
}

public void actionPerformed (ActionEvent evt) {


Object source = evt.getSource() ;
if (source == b1) {
// action sur b1
} else if (source == b2) {
// action sur b2
}
}
}

Recommandations de programmation 9/186


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
les interactions graphiques

La conception visuelle d’une interaction graphique est un véritable métier


qui fait appel à des compétences diverses concernant l’ergonomie et le
"design". L’objectif peut se résumer en un conseil particulièrement
difficile à suivre : FAIRE SIMPLE!
Quelques incitations ;

• Eviter de présenter trop de fonctions diverses sur un même écran.


L’utilisateur doit être concentré sur un petit nombre d’objectifs.
D’un autre coté il faut aussi éviter de disperser les interactions sur
une succession d’écrans de saisie (l’utilisateur ne sait plus se
situer, et la navigation est trop directive).

• Eviter la dispersion visuelle (même souci que précédemment).


Eviter les "papillotements" : objets graphiques dispersés sans que
des lignes de force apparaissent, contrastes graphiques fatigants,
arrivées d’informations ou animations intempestives.

• JAVA permet de faire de belles choses : profitez-en! Sachez


dépasser l’aspect "terminal de saisie grand systèmes" (une
succession de formulaires), l’aspect "tableau de bord d’avion" (des
informations partout, sur un fond gris) mais n’en faites pas trop
tout de même (certains designs très "mode" sont saisissants pour
vendre un produit mais insupportables pour une utilisation
journalière)

• Connaissez le métier de l’utilisateur. On ne conçoit pas de la même


manière une interaction s’adressant à un utilisateur novice (et qui
doit favoriser l’apprentissage) et une interaction pour un
utilisateur professionnel. Un "trader" qui travaille veut aller très
vite et préfére souvent pouvoir se limiter à quelques interactions
clavier, il souhaitera qu’après chaque action le "focus" aille en
priorité sur certaines zones, il souhaitera pouvoir configurer lui
même son poste pour en attendre certains comportements.

• Quelle personnalisations? Changer de police de caractères,


changer les accélérateurs, changer de palettes de couleur (vaut
mieux que de changer les couleurs trop librement),.. Pour un
"trader" ce qui est critique c’est la personnalisation de sa vision des
cours et de leur évolution, chacun a son truc et sa formule et sera
même prêt à écrire un programme JAVA spécifique! Profitez donc
de la dynamicité de JAVA pour définir une API d’extension...

Recommandations de programmation 9/187


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
répartition

Un des points forts de JAVA est de permettre de diffuser du code


"nomade" sur le réseau et de fournir tous les mécanismes de sécurité
associés à cette exécution dynamique et locale d’un code "étranger".

On peut utiliser des mécanismes prédéfinis comme celui des Applets,


ou on peut , au travers de RMI par ex., télécharger le comportement d’un
Objet et l’utiliser dynamiquement .

Un des choix fondamentaux de la répartition en JAVA est bien celui des


préalables : les partenaires d’un échange connaissent-ils avant l’échange le
détail du comportement des objets? par exemple RMI connait deux mode
de fonctionnement : un dans lequel les objets sont définis de chaque coté
(et l’on échange des instances), l’autre dans lequel on découvre
dynamiquement des objets nouveaux.
A chaque type de comportement sont associés des savoir-faires
spécifiques et des décisions stratégiques importantes.

Prenons le cas des Applets:

• Avantages : pas de problème de déploiement, le code (et donc le


protocole) est automatiquement à jour (dans les systèmes
client/serveur classique l’harmonisation des versions tourne au
cauchemar); Les mécanismes de sécurité sont pleinement actifs,
cela permet de s’adapter à toute une gamme de clients plus ou
moins "proches".

• Inconvénients : le téléchargement peut prendre du temps; les


contraintes de sécurité peuvent s’avérer trop contraignantes
(impressions locales, communications avec d’autre serveurs,...); le
contrôle d’exécution au sein sein d’un navigateur peut s’avérer
insuffisant pour certaines applications (on peut se retrouver avec
une transaction incomplète parcequ’un utilisateur peut passer à
autre chose...)
Au niveau graphique, il faut beaucoup de réflexion pour définir
une interface qui découvre dynamiquement des objets (et qui soit
de plus haut niveau que l’API des Applet) .

Recommandations de programmation 9/188


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
répartition (suite)

les protocoles
• La définition des protocoles doit permettre une évolutivité
maiximum: les actions élémentaires devraient être définies par
des interfaces; les paramètres des méthodes devraient être au
maximum encapsulés (c.a.d. être eux-même des objets ou des
interfaces); les objets passés doivent tenir compte des contraintes
de linéarisation et éviter les effets de bord (tous les paramêtres
sont passés réellement en copie); dans les types en retour prévoir
des extensions futures de code d’acceptation.
// delicat a maintenir
void creeClient(String nom, String id, String prenom);

// plus evolutif
Acceptation creeClient(Client client)
throws CreationRightsException, UniqueIDException;
// Acceptation peut contenir un certificat, un Objet
// qui en l’occurence p.e. un Client avec mise a jour
// d’un champ qui fixe un numero à ce client

• Veiller aux propriétés de linéarisation des objets (transient, etc.)


pour éviter de transférer plus d’informations que nécessaire.

• Définir le type de relation Client/Serveur :

• protocole sans état : le client établi une connexion, fait un


requête et la connexion est coupée. Le serveur ne conserve
aucun contexte.

• session sans conservation de connexion : Le serveur mémorise


l’appel du client et lui conserve un contexte.

• session avec conservation de connexion : une connexion reste


active pendant toute la durée du dialogue.

Recommandations de programmation 9/189


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
internationalisation

références :

documentation JDK docs/guide/intl/index.html

Comme pour le traitement des exceptions les mécanismes


d’internationalisation d’une application doivent être arrétés avant le
démarrage du codage (la réintroduction a posteriori de code
d’internationalisation est pénible et très facilement erronée).

Les objets de type java.util.Locale permettent de désigner une "aire


culturelle" (par ex. Français sous-variété Canadienne). A partir de cette
information il est possible de paramétriser des formats (formats de date,
de nombre, etc.) et des opérations sur chaînes (recherche de "mots", tri
alphabétiques). Le package java.util.text offre aussi des outils
permettant de paramétriser des désignations (ex. dans un menu) et des
messages (ex. messages d’erreur).

Au fur et à mesure que l’on enrichira les aires culturelles pour lesquelles
une application sera susceptible d’être intelligible, il faudra mettre à jour
des ressources contenant les versions localisés des messages ou des
formats de message (c.a.d. des chaînes de caractères contenant des
emplacements pour des valeurs renseignées par le programme : montants,
numéros de ligne, etc.).

Il faut donc organiser ces ressources en utilisant le mécanisme des


java.util.ResourceBundle qui permet d’organiser des hiérarchies
de ressources : ainsi si une information n’est pas spécifique à l’aire du
Canadien Français on la retrouvera dans l’aire du Français.

Un des choix fondamentaux est la manière d’indexer les messages : faut-il


opérer en passant par un nom symbolique
("erreur.securite.droit_creation") ou en utilisant directement le message
comme clef de recherche? Ce second choix est plus facile pour le
programmeur car il n’a pas à attendre de décision sur la définition d’un
nouveau type d’erreur et peut être immédiatement opérationnel pour des
tests. Par contre il n’est pas réalisable avec le mécanisme par défaut
(PropertyResourceBundle) et il peut conduire à une dispersion des
types d’erreurs. Il faut, de plus, construire un outil qui extraie (et qui
maintienne) automatiquement la base des messages de l’application.

Recommandations de programmation 9/190


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9
intégration des méthodes natives

Un code natif est potentiellement un point faible à la fois pour la sécurité


et pour la robustesse générale de l’application.

Sur ce dernier point quelques "recettes" concernant JNI:

• Toujours tester les résultats de retour des fonctions découvrant


dynamiquement des classes, attributs, méthodes,..
(FindClass, get*ID): l’utilisation, par la suite, de
désignations JAVA inexistantes, est une garantie d’accident
grave.

• Vérifier si une exception n’a pas a été levée chaque fois qu’une
fonction d’interface appelle du code JAVA susceptible de
déclencher un exception.

• Sauf pour des "petits" codes natifs penser à protéger l’exécution


par captation des signaux (y compris ceux signalant une
violation mémoire grave) -voir fonctions standard C signal..-.

• Ne pas conserver des références locales, ne pas les passer entre


Threads, s’assurer de l’appariement des fonctions réservant des
zones mémoires et de celles qui les libèrent (variables globales,
"punaisage"). Utiliser le "punaisage" partiel pour de gros
tableaux.

... et, bien entendu, isoler soigneusement tout code posant des problèmes
de portabilité (facilité de maintenance, de portage) ou des problèmes de
sécurité (essayer d’avoir une politique cohérente de sécurité avec le code
JAVA lui-même -à partir de JAVA 1.2 on peut définir une politique de
sécurité pour des applications "locales"-).

Recommandations de programmation 9/191


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
9

Recommandations de programmation 9/192


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
L’atelier de développement 10

Objectifs
Ce chapitre constitue un aide-mémoire1 pour la réalisation d’une chaîne
de production JAVA. On y trouvera :

• Une liste des fonctions et des outils susceptibles de constituer


une telle filière.

• Des indications sur les points à surveiller. Ces critères ne sont


pas extensifs mais peuvent servir de point de départ à des
réflexions sur le choix et le calibrage des outils.

Le marché des outils JAVA évoluant très vite il est conseillé de consulter
les sites qui les recensent (par ex. javaworld)

1. Ce chapitre ne développe pas l’architecture générale d’une chaine de


développement : on reste dans le contexte d’un projet classique, les
organisations adaptées à l’approche par composants (CBSD) nécessitent des
stratégies particulières.
Référence générale à consulter : http://www.sei.cmu.edu/technology/str

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
introduction : R.A.D et/ou maîtrise du code de base?

Le developpement logiciel est souvent décrit comme passant par les


phases suivantes :

• Analyse

• Conception

• Réalisation/codage

• Tests

• Révisions

Toutefois si on tente de réaliser ces phases les une après les autres tout en
appliquant des règles sévères de qualité on court des risques importants
de dérive (évolutions des besoins non prises en compte par la réalisation,
difficultés imprévues de réalisation qui obligent à revoir la conception,
etc.).

Le cycle de développement optimum est le plus souvent une "spirale"


dans laquelle on procède par itérations successives. La réalisation d’une
maquette, puis de prototypes avec raffinements successifs permettent de
réinjecter les leçons de la réalisation dans l’analyse et la conception. Les
tests, présents dans toutes ces phases, permettent de calibrer le produit en
préparation et de marquer de manière incontestable l’avancement du
projet (ce qui est éventuellement utile pour débloquer des financements!).

Pour accélérer le cycle de développement un certains nombres d’outils,


dits de R.A.D. (Rapid Application Development), permettent, au travers
d’interfaces essentiellement interactives , d’intégrer des composants
spécialisés (interactions utilisateurs, accès aux bases de données,
client/serveur, etc.).

Au delà de la grande diversité de ces produits il faut savoir apprécier


leurs limites et savoir adapter la qualité de fabrication du code en
fonction des moyens et des objectifs poursuivis: veut-on fabriquer un
logiciel pour une diffusion restreinte ou pour une diffusion large? quelles
sont les marges d’adaptabilité que l’on se fixe? quels sont les objectifs de
fiabilité ? etc.

L’atelier de développement 10/194


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
introduction : au delà du R.A.D?

Quelques critiques courantes concernant les outils de R.A.D :

• On est tenté de confondre "maquette" et "produit".


De plus l’interaction utilisateur EST l’application : on tend à
économiser sur la phase de conception ce qui est mauvais pour
l’abstraction, l’architecture du logiciel, l’évolutivité. La mise en
place de tests systématiques devient difficile.

• L’outil de R.A.D. est indissociablement lié à des composants


"proprétaires" que ce soit dans la phase de conception ou dans
la phase d’exécution.
L’enrichissement de la conception à l’aide de composants
définis par le programmeur est limité.
Par ailleurs le produit livré en clientèle suppose souvent la
présence de binaires spécifiques (problèmes de royalties, de
portages, de maintenance,...). Dans d’autres cas c’est le code
généré qui est opaque et difficile à debuguer et maintenir.
De plus on ne peux pas avoir des composants interchangeagles
qui permettraient de modifier des détails de comportement (ex.
modalités d’échanges client/serveur).

Une des grandes forces des environnements JAVA est de permettre de


graduer le choix des outils et de les combiner en fonction des objectifs:
le marché offre des outils très divers allant de la génération rapide de
maquettes jusqu’à la filière de production "lourde". On peut concevoir en
JAVA un outil de RAD débarrassé des défauts ci-dessus et le faire
coopérer, en amont ou en aval, avec des filières de contrôle étroit du code.
Il y a dans JAVA lui-même des dispositifs qui facilitent la production du
logiciel, citons pour exemple:

• L’organisation par "objets", la dynamicité, les APIs ("Beans" en


particulier). On a la possibilité de définir de véritables
composants réutilisables (soit directement soit par dérivation
de composants existants). Les outils eux-mêmes ont la
possibilité d’intégrer dynamiquement ces composants (ex.
"beanbox").

• La prise en compte des leçons de la filière C/C++ : élimination


des constructions dangereuses, portabilité, liaisons code-
documentation, etc. Par ailleurs les outils de production JAVA
profitent des démarches abordées dans ces filières précédentes.

L’atelier de développement 10/195


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
L’intégration des outils, les ateliers

Une chaîne de production professionnelle n’est pas destinée à un seul


acteur, elle doit impliquer des personnes ayant des rôles différents depuis
le programmeur jusqu’au chef de projet. Il est important que les outils
impliqués dans les différentes phases puissent se coordonner facilement.
De plus certaines tâches sont purement interactives, d’autres relèvent au
contraire de tâches de fond en batch.

Il est de pratique courante de lier les productions des différents outils au


travers de scripts exploitant des fichiers (sources, binaires, traces, etc.) et
des règles de déclenchement (Makefile)

Les "ateliers" de programmation, qui sont au centre de l’activité de


production, doivent faire preuve d’un minimum d’ouverture soit en
exportant leurs fichiers et des règles cohérentes d’accès à ces fichiers, soit
en publiant une API d’accès à leurs ressources.

Les API d’accès en JAVA devraient normallement connaître un fort


développement à la fois pour assurer ces liaisons et pour permettre des
personnalisations approfondies des outils.

Exemple : de nombreux ateliers sous-traitent la partie "gestion de version"


à des produits tiers; la présence d’une API permet de changer le produit à
qui cette tâche est confiée.

L’atelier de développement 10/196


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
analyse et conception

La notation UML va permettre d’harmoniser le langage des descriptions


des systèmes décrits à l’aide des concepts objets.

Si les outils d’analyse et de conception sortent du cadre de ce cours on


retiendra toutefois qu’ils n’échappent pas à la nécessité d’assurer une
coordination avec l’ensemble du processus de production de logiciel.

Le cas le plus délicat est celui de la génération automatique de code. Les


squelettes de code générés sont amenés à être complétés et modifiés, le
corps des méthodes va être décrit, etc. Il faut que soient facilités :

• La reprise du code existant dans des spécifications modifiées.

• La modification des spécifications elles-mêmes par reinjection


des modifications acquises dans le code.

• La liaison avec les systèmes de gestion de version de code


(établissement de la version des spécifications : voir
java.lang.Package à partir de la version 1.2)

L’atelier de développement 10/197


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
L’éditeur

Au delà de qualités classiques d’ergonomie un éditeur de programme


source sera plus riche s’il dispose :

• d’une connaissance de la structure des programmes JAVA.


L’éditeur peut reconnaître et mettre en valeur les "blocs" du
langage et les zones réservées aux commentaires et à Javadoc.
Il peut ainsi permettre de vérifier les appariements des
accolades et des parenthèses; il peut colorier de manière utile
(et paramétrable!) les en-têtes de déclaration (classes et classes
internes, constructeurs, méthodes, variables); il peut filtrer les
zones que l’on veut voir apparaître à l’écran (effets de "zoom" :
visualisation du squelette du code, filtrages sur Javadoc); il
dispose de "pretty-printing" avec colorisation et filtres; etc.
Exemple : les éditeurs de la famille Emacs permettent de
reconnaître des structures et de programmer des
comportements.

• d’une connaissance du langage JAVA.


On a une édition sous contrôle qui prépare le travail du
compilateur puisqu’on ne peut plus éditer de syntaxe illégale.
La connaissance des objets du programme facilite la
complétion automatique ou assistée (quels sont les champs ou
méthodes possibles pour cette instance?).

• d’une laision aisée avec d’autres programmes : liens


automatiques avec les messages d’erreur du compilateur; suivi
des actions d’un debugueur; liens avec un navigateur, un outil
de recherche, une aide en ligne liées à des composants, etc.

Exemple : colorisation sous Xemacs

L’atelier de développement 10/198


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
Outils annexes à l’éditeur

Ce sont les outils externes qui collaborent avec l’éditeur pour améliorer le
confort de la programmation.

La consultation en ligne de la documentation des classes et la qualité de la


navigation dans cette documentation sont des points essentiels.

Un outil comme SNIFF permet de rechercher des classes, de mesurer


rapidement l’impact d’une modification en recherchant dans le code
toutes les utilisations d’une méthode, etc.

L’atelier de développement 10/199


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
L’aide à la conception d’interaction

Il est séduisant d’envisager de générer des programmes à partir d’un


outil permettant de mettre en place interactivement des objets graphiques,
mais il convient de bien prendre en compte les points suivants :

• Il faut que l’outil sache mettre en place des LayoutManagers


au lieu de faire du positionnement en absolu.

• Il faut que l’outil sache mettre en place des composants définis


par des parties tierces (Beans) sans imposer que ces
composants intègrent des classes spécifiques à l’outil.

• Il doit être facile d’intervenir dans le code généré ( en


particulier au niveau de l’architecture de gestion des
événements). Toute modification dans la disposition doit
permettre de respecter le code déjà écrit.
Une solution élégante consiste en la génération d’une ressource
sous forme texte qui décrit la disposition et qui est interprété
au run-time (dans ce cas un composant spécifique d’exécution
doit effectivement être livré avec l’outil)

• Attention à la dynamicité des composants!


Exemple : l’utilisateur d’un Network Computer doit pouvoir
disposer d’un profil qui personnalise ses objets d’interactions.
Ainsi on doit être capable de gérer une barre d’outils dans
lequel le nombre d’éléments n’est pas connu à l’avance.

L’avenir de ce type d’outils se situe du coté des assembleurs de Beans.


On a ainsi des possibilités de découverte des capacités des composants,
des personnalisations éventuelles de la mise en oeuvre, etc. Les
assembleurs de Beans vont au delà des composants graphiques et
permettent aussi de spécifier des modalités d’ échanges d’informations
entre composants.

L’atelier de développement 10/200


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
Gestion des sources

principes
Les outils de gestion de sources permettent :

• d’archiver les versions successives de chaque fichier source.


On peut ainsi marquer un logiciel avec une indication de la
version de tous ses composants et reconstituer une version
antérieure (suivi de bug. par ex.).

• gérer la concurrence d’accès sur les sources : un développeur


peut s’assurer l’exclusivité d’une mise à jour. Les outils les plus
sophistiqués permettent des évolutions en parallèle entre des
sites distant avec des procédures de reharmonisation.

• d’assurer des services annexes (dépend des produits) : suivi


des bugs et corrections, gestion de configuration (voir chapitre
livraisons), etc.

Le point clef d’une politique de gestion de version est celui de la


signification des niveaux de version et de l’ordonnancement (à un certain
niveau il n’y a plus d’ordre historique entre deux feuilles situées sur des
branches différentes de l’arbre des versions).

outils
Outils standards liés à des systèmes d’exploitation : SCCS, RCS, PVCS,

Outils spécifiques (s’appuyant éventuellement sur les précédents) :


JAVASAFE (JavaSoft),TEAMWARE, etc...

L’atelier de développement 10/201


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
Gestion des sources

points
JAVA pose des problèmes particuliers dans la gestion de version. En effet
une "application" peut faire appels à des composants différents. Ces
composants peuvent avoir diverses origines et donc relever chacun d’une
gestion de version qui leur est propre : chaque version d’application est
susceptible de fonctionner sur des combinaisons possibles de versions de
composants. Lorsque ces composants sont chargés dynamiquement les
incompatibilités apparaissent au run-time.

"Java Product Versionning Specification" pose des jalons pour l’émergence de


pratiques standard:

• A la base, les informations publiques de version (celles qui sont


accessibles après livraison) s’appliquent au niveau package. Le
package constitue le niveau atomique d’objet soumis à version.
Un produit est distribué en archivant des packages et est
identifié avec son propre numéro. (Les identifications sont
portés dans les fichiers Manifest situés dans les archives .jar)

• Apparue à partir de la version 1.2 la classe


java.lang.Package distingue les versions de spécifications
des versions de réalisation. La version des spécifications
désigne les interfaces d’appels des classes et permet
éventuellement de gérer les compatibilités au niveau des
appels des services rendus par ces classes. La version de
réalisation gère les modifications dans l’implantation
(corrections de bugs, etc.).

L’atelier de développement 10/202


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
Gestionnaires de maintenance

Le gestionnaire de version doit être exploité pour suivre la maintenance.

Les bugs, les anomalies sont reportés dans une ressource. Par la suite on
utilise cette ressource pour suivre les opérations : qualification du bug,
documentation, inscription dans une base de connaissance pour le help-
desk, opérations de correction (et modification de la base de test), insertion
dans une nouvelle version (ou suivi de la livraison de corrections
d’urgence).

Des outils très complets de Help-desk ( ex. Remedy) : peuvent être


personnalisés pour assurer ces fonctions.

La coopération de différents outils par échanges d’informations est ici


aussi très importante : la gestion des anomalies doit être coordonnée avec
les autres projets d’extension/modification (planning, ressources,
WorkFlow etc.)

L’atelier de développement 10/203


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
Documentation de code, aide en ligne

Un projet complet génère une importante documentation. De manière


non-exhaustive citons: les documentations de spécification, la
documentation du code, la documentation d’utilisation des classes, la
documentation d’utilisation d’un produit, la documentation utilisateur en
ligne... sans compter les documentations de suivi de projet, d’évolution,
etc.

Il faut pouvoir générer cette documentation, la consulter, gérer les


versions, s’assurer qu’elle suit bien les évolutions de ce qu’elle
documente, pouvoir la filtrer (par exemple séparer la documentation
précise du code de la documentation de classe), l’analyser pour rechercher
des mots-clefs, etc.

Cette gestion devient difficile si chaque outil génère un format particulier,


ne sait pas importer/exporter la documentation générée, ne fournit pas
un format structuré analysable facilement. Un format décrit en SGML a
l’avantage de permettre ces manipulations par programme.

• Javadoc facilite une meilleure intégration code-


source/documentation de classe et fournit une construction
documentaire hyper-texte de bon niveau.
Un mécanisme de personnalisation des formats (Doclets) est
apparu depuis la version 1.2.
Quelques possibilités généralement oubliées : filtrer la
documentation des membres en fonction de leur statut privé,
public, etc.; sortie en format PostScript.

• L’API JavaHelp permet la mise en oeuvre d’une aide en ligne. Les


ressources d’aide peuvent être situées sur le site client ou sur le
réseau, Le mécanisme sait coopérer avec d’autres logiciels comme
des moteurs de recherche.

• Les moteurs de recherche (ex. Excite) peuvent être utilisés à la


fois dans l’atelier de programmation et dans les aides en ligne.

L’atelier de développement 10/204


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
Debug

Un outil de Debug permet de suivre le déroulement d’une exécution :


pose des points d’arrêt (sur incident, en un point précis, sur une
condition), exécution pas à pas, examen de la pile, de l’état d’objets
(instances, threads, groupe de thread), modifications interactives de
valeurs, appel interactif de méthodes, etc.

La concurrence (threads) à l’intérieur de Java et la répartition des


applications peut nécessiter l’intervention de débugueurs sophistiqués
capables d’observer plusieurs processus (éventuellement situés sur des
machines différentes), capables d’observer des verrous sur des instances
ou des classes, etc.

La liaison avec un debug du code de méthodes natives pose également


des problèmes complexes.

outils
Généralement fournis avec les ateliers de développement et liés à une
JVM. ex: jdb avec le JDK

Exemple de produit autonome: JWatch

L’atelier de développement 10/205


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
génération (make)

On peut décrire la génération d’un produit comme un enchainement de


compilations (et/ou d’autre tâches). En pratique la somme des tâches à
exécuter est trop importante pour être déclenchée chaque fois que l’on
apporte une modification au cours du développement ou de la
maintenance. On cherche donc à ne déclencher que le minimum d’actions
qui permettent d’aboutir à un état complet d’une portion du projet.

Traditionnellement la description des actions à déclencher en cas de


modification se fait par l’intermédiaire d’un utilitaire de type Make (le
fichier de description est appelé Makefile) - voir par ex. le produit domaine
public "GNU Make" ("http://www.fsf.org/software/make/make.html")-..
Dans un Makefile on décrit des objectifs et des règles de dépendances entre
fichiers : un fichier B doit avoir une date de modification ultérieure à celle
d’un fichier A, dans le cas contraire (ou si B n’existe pas) on décrit les
actions qui permettent de créer ou de mettre à jour B. La formalisation de
ces règles suit une syntaxe particulière. Exemple :
.c .o:
$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<

Dans un projet JAVA le Makefile n’est toutefois pas impliqué dans le


processus de compilation lui même (pour passer des ".java" aux ".class").
En tenant compte des capacités de chargement dynamique de JAVA le
compilateur assure lui-même une mise à jour plus optimisée que celle
d’un Makefile classique. Il faut donc correctement s’organiser (voir
architecture des répertoires de package) et bien comprendre ce
fonctionnement du compilateur: s’il compile une classe il vérifie les
classes immédiatement référencées dans le code courant; si la classe
référencée n’est pas à jour il tente de la recompiler MAIS il ne vérifie pas
les dépendances pour les classes qu’il ne recompile pas (sauf à préciser
l’option -depend il ne recompilera pas une classe C modifiée et
référencée par une classe B à jour et elle même reférencée par une classe A
qui fait l’objet de la compilation).

Les Makefile sont utilisés par contre pour générer des fichiers ".jar", pour
recompiler des méthodes natives, pour générer des documentations,
passer des tests, etc. Attention : les scripts associés aux règles sont
dépendants de la nature de la plate-forme de production.

L’atelier de développement 10/206


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
tests

principes
On peut catégoriser les tests en fonction de périmètres (tests de
composants, tests d’application), de positionnement dans la vie du
logiciel (tests de non-regression,...), de nature (tests fonctionnels, de
charge, etc.).

Bien que les catégories suivantes se recoupent elles sont commodes pour
caractériser des outils ou des procédures de tests :

• tests fonctionnels : vérifications conformité aux spécifications;


productions de résultats conformes ; contrôles sur les
contraintes;...

• tests aux limites : proches du cas précédent sur les contrôles


des cas illégaux; accent mis sur des combinaisons de valeurs
remarquables (grandes, petites) pour tester les capacités du
logiciel (taille des données, nombre de cas, précision des
calculs, valeurs particulières...)

• tests de charge : simulation de situations réelles; calibrage du


logiciel, capacité à servir des nombreux utilisateurs
simultanément, grand nombre de données, etc..

• tests d’interface : "rejouer" automatiquement des interactions


utilisateur; conformité des comportements; enchainements sur
des comportements fonctionnels équivalents,..

produits
SunTest fournit des outils de tests eux-mêmes écrits en JAVA : JAVASPEC
(tests fonctionnels); JAVASTAR (tests d’interface); JAVALOAD (tests de
charge client-serveur)

L’atelier de développement 10/207


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
tests

points
La mise au point de tests fonctionnels est particulièrement intéressante
lorsqu’on s’adresse à des Interface JAVA . En effet, du fait du
polymorphisme, pour le même appel de méthode on pourra avoir des
réalisations effectives différentes et il peut être intéressant de controler
toutes les parties cachées du "contrat" d’interface.

Il y a des limites à une génération automatique d’une combinatoire de


tests (voir mesures de la testabilité). Il est vivement recommandé de
mettre au point pour les grands composants d’une application un
mécanisme de test prenant en entrée des scenarios décrits sous forme de
texte et produisant du texte comme résultat.

• Les scenarios pourront être enrichis rapidement dans la vie du


logiciel au fur et à mesure que de nouvelles anomalies sont
détectées. Quand ces anomalies sont corrigées on a ainsi les
moyens de controler la non-regression des version ultérieures

• L’analyse des résultats se fait rapidement par des outils de


comparaisons de texte (limite: lorsque des valeurs dépendent
de la date ou de la localisation courante!)

L’atelier de développement 10/208


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
analyse de couverture

Il faut avoir des indications sur l’étendue de la couverture des tests : dans
quelle mesure ont-ils permis de passer par toutes les branches du code?

Avant de passer les tests fonctionnels on doit "instrumenter" de code, c’est


à dire le recompiler de manière à ce que l’exécution puisse tracer le
passage dans les différentes parties.

Un outil d’analyse de couverture (ex. JAVASCOPE de Suntest) permet


d’instrumenter puis d’analyser ensuite la couverture (production
d’informations spécifiques à des parties du code, métriques diverses -dont
taux de couverture-)

L’interprétation globale des résultats est délicate : il faut savoir filtrer des
parties exceptionnelles du code qui ne sont pas pertinentes pour obtenir
un bon taux de couverture. Par ailleurs les informations obtenues ne
préjugent pas de la pertinence fonctionnelle des tests : les informations
les plus précieuses se trouvent dans le détail des parcours des "branches"
de l’arbre des appels et il faut savoir les rechercher.

L’atelier de développement 10/209


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
analyses de performances

principes
En exécutant du code Java avec un moniteur spécial (par exemple en
utilisant l’option de profiling -prof de la commande java) on peut
générer des informations donnant des indications sur la "consommation"
de chaque appel de méthode.

Pour être significatifs les tests qui servent analyser les informations de
performances doivent être représentatifs de conditions réelles d’exécution.
En effet l’objectif n’est pas d’optimiser tout le code mais les quelques
points qui peuvent réellement poser des problèmes significatifs.

La "consommation" a de multiples facettes. Tous les systèmes d’analyse


proposent des informations du type : temps cumulé passé dans une
méthode, nombre d’appels d’une méthode ( et donc des ratios: méthodes
les plus couteuses en temps cumulé, méthodes pour lesquelles chaque
appel est couteux, etc.). Selon les outils on peut aussi obtenir des
informations sur les graphes des appels, le nombre d’instances générées
par classe et l’utilisation de la mémoire, l’utilisation des Threads, etc. . On
peut également obtenir des informations de trace au cours de l’exécution
elle même.

outils
Il y a des outils qui exploitent les traces standard du profiling JAVA
(HyperProf, JWS) et d’autres plus sophistiqués (JProbe, "Optimize
It") qui utilisent des moniteurs spécifiques.

points
Il est essentiel de pouvoir filtrer les informations : on détecte les "points
chauds" et on élimine les données qui concernent les autres classes.

Attention: un même code java peut s’exécuter sur des JVM différentes:
interprété, JIT, "HotSpot".

L’atelier de développement 10/210


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
Analyses statiques du code

principes
Sans recourir à une exécution on peut avoir des informations sur la
qualité du code en ayant recours à des analyseurs statiques. On trouve ici
deux catégories d’outils : les "débourreurs" et les outils de "physique du
logiciel".

• Sur le modèle du programme standard C Lint un "débourreur"


analyse le code pour tenter de détecter des constructions
potentiellement dangereuses.
Un tel outil dispose d’une base de savoir-faires et de règles et
produit des diagnostics argumentés (et faisant référence à des
portions de code source).

• Les outils de physique du logiciel analyse la complexité et la


testabilité des programmes. Ils calculent des métriques :
complexité cyclomatique, complexité de Halstead, etc.

outils
Détecteurs de constructions critiques : CodeWizard, etc,
L’outil de test JavaPureCheck est aussi à mettre dans cette catégorie
(bien que spécialisé dans les problèmes de portabilité)

Physique du logiciel : TotalMetric,...

points
Les qualités d’un débourreur se jugent sur la pertinence de ses règles, la
capacité à filtrer ces règles ou à désarmer localement l’application d’une
règle (dans un commentaire)

L’interprétation des mesures de complexité demande une grande


expérience.

L’atelier de développement 10/211


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
préparation à la livraison

Une fois que l’état d’avancement du projet est tel que l’on peut procéder à
des livraisons on ne peut directement transférer des binaires ou des
ressources directement depuis l’espace de développement. Voici quelques
suggestions pour mettre en place des procédures qualité très strictes:

1. Mettre en place un environnement "vierge" complètement étanche


par rapport aux environnements de développement existants.

2. Extraire des archives la version courante des sources et des


ressources

3. Lancer la génération des binaires avec toutes les options


appropriées (optimisations, pas de traces ni d’information de
debug, etc.)

4. Transformations éventuelles du code pour marquage, brouillage...

5. Exécution des tests et contrôles. -éventuellement sur des plate-


formes multiples-

6. Génération et contrôle des documentations

7. "Empaquetage" des livraisons et tests de la validité des procédures


de livraison/installation

8. Mise en place des liens avec les mécanismes de livraison


automatique, de Help-Desk, de gestion, etc.

Sauf exception l’enchainement est absolu : tout échec sur une phase doit
entraîner une reprise à zero de tout le processus.

L’atelier de développement 10/212


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
livraison/déploiement

Applet ou application autonome? Le choix est important pour organiser le


déploiement du logiciel et surtout pour garantir le suivi rapide des
évolutions :

• Avec une Applet on a un client qui charge son code avant de


s’exécuter, tous les clients sont assurés ainsi de disposer de la
dernière version du code . Toutefois :

• Il faut équilibrer les regroupements de classes et de ressources


sur plusieurs archives ".jar" et il faut éviter de charger une trop
grande quantité de code d’un seul coup.

• Les restrictions de sécurité prennent leur plein effet (ce peut-


être un avantage ou un inconvénient)

• Il n’est pas garanti que toutes les librairies standard soient à


jour du coté client.

• Avec une application autonome on doit mettre en place des


procédures de livaison/installation. On peut utiliser des produits
(InstallShield, InstallAnyWhere,..) qui permettent de
packager un logiciel et d’automatiser les procédures d’installation
(avec lecture d’un contrat de licence, installation de licence, etc.).
Ces logiciels simplifient en outre la livraison par chargement direct
au travers du réseau. Toutefois :

• La mise à jour n’est pas assurée et il faut mettre en place des


procédures particulières.

• Il peut s’avérer intéressant de "packager" une application JAVA,


sa JVM et ses classes standard (voir JRE)

• Pour utiliser au mieux les dispositifs de sécurité JAVA il faut


utiliser au minimum la version 1.2

• Une solution intermédiaire existe : l’utilisation des technologies


PUSH (ex. Castanet de Marimba). L’application autonome est
stockée sur le poste client mais avant utilisation elle se connecte au
serveur pour éventuellement faire une mise à jour différentielle
des sources.

L’atelier de développement 10/213


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
10
autres outils

décompilateurs/brouilleurs
Les fichiers "binaires" JAVA facilitent l’inspection du code et le passage
d’un bon décompilateur donne une idée assez précise du contenu du
source.

On trouve donc à la fois des décompilateurs et des brouilleurs


("obfuscator") qui transforment un code JAVA de manière à le rendre
difficile à décompiler.

Les identifiants prennant des formes bizarres il faut conserver dans


l’atelier de développement un dictionnaire permettant de reconstituer le
nom réel à partir de la forme brouillé (ceci est nécessaire si on veut
récupérer et comprendre des messages d’erreurs imprévus). Il faut savoir
aussi ne pas tout brouiller, en particulier lorsque le code contient des
recherches dynamiques par nom (introspection, Beans)

En pratique un bon décompilateur arrive à donner une image fidèle de la


structure du programme : c’est l’absence d’identifiant significatif qui
trouble la compréhension.

outils syntaxiques
• Pour des raisons de robustesse du code, Java n’utilise pas de
préprocesseur : l’utilisation de macros risque de conduire à un
texte "lisible" qui est différent du code réellement compilé.
Différents produits proposent des macro-processeurs pour JAVA :
l’utilisation doit être limitée (ex. macros de trace, marquage des
messages à internationaliser) et ne pas concerner des parties
critiques du code

• Des analyseurs acceptant des grammaires sophistiquées sont


disponibles
voir JavaCC "http://www.suntest.com/JavaCC"

L’atelier de développement 10/214


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
aide mémoire outils 11

2
Objectifs
Ce chapitre constitue un aide-mémoire simplifié d’utilisation pour des
outilsl JAVA

• JAVAWorkshop est le premier atelier “ouvert” écrit en JAVA

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
11
JavaWorkshop: Gestionnaire de projets

JWS connaît deux niveaux d’organisation : le projet (project) et le


portefeuille (portfolio).

Un “projet” est une unité d’organisation liée à la génération.

Un projet a pour objectif de générer un produit “livrable” (application


autonome, Applet, Bean) ou un package.

Un projet peut s’appuyer sur d’autres projets qui sont nécessaires à sa


génération : ces projets sont vus alors comme des sous-projets du projet
principal.

Un “portefeuille” est une collection de “projets”.

Mise en oeuvre du “Project Manager”


Pour obtenir la fenêtre “project manager” cliquer sur l’icône
correspondante ou lancer depuis le menu principal par :
project ➔ show project manager

aide mémoire outils 11/216


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
11
JavaWorkshop: Gestionnaire de projets

créer ou importer un portefeuille


File ➔ new ➔ portfolio
File ➔ add ➔ portfolio

Création : préciser le nom d’un fichier (suivi de .psf) ce fichier sera créé
dans le sous-répertoire “jws” du répertoire d’accueil de l’utilisateur. Il est
possible de préciser un autre répertoire
(attention référence stockée sous forme de cheminom relatif dans le fichier
$HOME/jws<version>/portfolios)

créer ou importer un projet


Sélectionner un portefeuille dans l’arbre des projets (fenêtre “project
manager”)
File ➔ new ➔ project
File ➔ add ➔ project

Il apparaît alors une fenêtre de dialogue :

• cliquer sur le type de projet (Standalone, applet, bean, package)

• cliquer sur le type de GUI (no GUI, ou “gui created manually”)

• > Next

• préciser le répertoire dans lequel sera créé le projet (et


éventuellement préciser si des fichiers existants sont à conserver
dans le projet)

• dans le cas d’un package il faut donner le nom du package, et le


nom du répertoire “racine”des classes (équivalent de celui précisé
par l’option -d de javac),

Dans le cas d’un sous-projet on opérera cette création/importation en se


positionnant dans le projet englobant.

aide mémoire outils 11/217


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
11
JavaWorkshop: Gestionnaire de projets

fixer les attributs d’un projet


Cette opération permet de fixer un ensemble de conditions pour la
génération et l’exécution d’un projet
Project➔ edit

Il apparaît alors un dossier à onglets:

• General- informations générales : nom, type, répértoire sources,


sous-projet (informations fixées à la création)
point important : l’ordre des sous-projet fixe l’ordre des
compilations (d’ou la possiblitéde modifier l’ordre des sous-projets
dans la liste)

• Build- permet de fixer les informations utiles pour la


compilation: options du compilateur (-g pour le debugger est
proposé par défaut), répertoire d’accueil des classes (pour option -
d de javac), éléments complémentaires du CLASSPATH (nota: on
peut lancer jws avec option -classpath)

• Debug/Browse- permet de fixer les options pour l’outil de debug:


Chemins d’acces à rajouter pour visualiser les sources des classes
Point d’entrée : classe avec main, applet avec init
La page HTML associée au lancement (cas d’une Applet)
Options de l’interpréteur java (pour application autonome)
Outil de visualisation à utiliser pour une Applet
Type de debug (local ou sur machine distante)

• Run- options de lancement de tests (hors debug):


Pour un programme autonome : point d’entree, options
d’execution, paramètres de lancement
Pour une applet : definition des paramètres d’applet dans le
HMTL

aide mémoire outils 11/218


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
11
JavaWorkshop: édition, compilation, tests

édition
Dans project manager:
File ➔ new ➔ file

pour créer un fichier dans projet courant


File ➔ add ➔ file

pour l’ajouter dans projet courant

personnalisation de l’édition
Dans fenêtre édition :
Preferences ➔ source editor
Preferences ➔ keyboard

contrôle d’accès et version


Pour le choix de l’outil
Preference ➔ Version Control

enregistrement dans le système de versionnement


File ➔ version ➔ check In New

pour creation de l’enregistrement

checkIn : pour enregistrement

checkOut : pour mise en edition

Remarques: à l’enregistrement il y a demande de commentaires, mais il


n’y pas de versionnement fin.

aide mémoire outils 11/219


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
11
JavaWorkshop: édition, compilation, tests

compilation
Build ➔ Build

recompile les fichiers qui ont changé depuis la dernière recompilation du


projet
Build ➔ Build All

recompile tous les fichiers du projet


Build ➔ compile file

permet de ne compiler que le fichier en édition


Preference ➔ builder

permet de choisir le compilateur à impliquer

La fenetre Build donne les erreurs (qui sont signalées dans l’éditeur de
code lui-même)

test
Lancer
Project➔ run

(voir options pour lancements Applets)

aide mémoire outils 11/220


Intitulé Cours: L’atelier de developpement JAVA
Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98
Sun Microsystems France

La couverture des agences de Sun France permet de répondre à


l’ensemble des besoins de nos clients sur le territoire.

Table 11.1 Liste des agences Sun Microsystems en france


Sun Microsystems France S.A Agence d’Aix-en-Provence
13, avenue Morane Saulnier Parc Club du Golf
BP 53 Avenue G. de La Lauzière
78142 VELIZY Cedex Zone Industrielle - Bât 22
Tél : 01.30.67.50.00 13856 AIX-EN-PROVENCE
Fax : 01.30.67.53.00 Tél : 04.42.97.77.77
Fax : 04.42.39.71.52
Agence de Issy les Moulineaux Agence de Lyon
Le Lombard Immeuble Lips
143, avenue de Verdun 151, boulevard de Stalingrad
92442 ISSY-LES-MOULINEAUX Ce- 69100 VILLEURBANNE
dex Tél : 04.72.43.53.53
Tél : 01.41.33.17.00 Fax : 04.72.43.53.40
Fax : 01.41.33.17.20
Agence de Lille Agence de Toulouse
Tour Crédit Lyonnais Immeuble Les Triades
140 Boulevard de Turin Bâtiment C - B.P. 456
59777 EURALILLE 31315 LABEGE Cedex
Tél : 03.20.74.79.79 Tél : 05.61.39.80.05
Fax : 03.20.74.79.80 Fax : 05.61.39.83.43
Agence de Rennes Agence de Strasbourg
Immeuble Atalis Parc des Tanneries
Z.A. du Vieux Pont 1, allée des Rossignols
1, rue de Paris Bâtiment F - B.P. 20
35510 CESSON-SEVIGNE 67831 TANNERIES Cedex
Tél : 02.99.83.46.46 Tél : 03.88.10.47.00
Fax : 02.99.83.42.22 Fax : 03.88.76.53.63
Bureau de Grenoble
32, chemin du Vieux Chêne
38240 MEYLAN
Tél : 04.76.41.42.43
Fax : 04.76.41.42.41

Intitulé Cours: L’atelier de developpement JAVA


Client : Sun Service Formation Révision : D
Réf. Sun : LJ300 Date : 20/7/98

You might also like