Différents
langages de programmation (sommaire)
--------------------> Un exemple complet à consulter après la lecture de cette page je pense !
Passage de paramètres dans une applet
Fonctions polymorphes (le polymorphisme c'est quoi ?)
L'utilisation du package graphique awt
Les entrées sorties (Supprimer des fichiers temporaires ?)
Lecture E/S par ligne avec gestion des exceptions
Lecture E/S par caractères avec gestion des exceptions
Gestion des sockets (TCP/IP : flux de données) Client -> Serveur
Gestion des sockets (TCP/IP: flux de données) Clients (+sieurs) -> Serveur
Gestion
des communications (UDP: datagrammes)
Gestions
des sockets avec gestions du package Swing
Applications
distribuées, objets distants, RMI
Avant toute chose, il vous faut
télécharger le SDK
(J2SE)sur le site de Sun : veuillez dans la mesure du possible vous procurer la
dernière version du SDK qui contient le compilateur javac et l'exécutable
Java.
Sélectionnez le produit correspondant à votre système
d'exploitation (WIN 32 pour Windows 95 et 98). Le JDK 'pèse' environ 8,4 Mo.
Prévoyez donc un peu de temps...
Pour Windows 95 ->
Mettre dans l'autoexec.bat >mettre
SET PATH=c:\répertoired'installationdewinnedit;%PATH%
puis :
SET PATH=c:\répertoired'installationdewinnedit\bin;%PATTH%
CLASSPATH=.;c\répertoired'installationdewinnedit\classes;répertoired'installationdewinnedit\classes.zip
-> plus besoin à partir du jdk 1.3.
Pour 98/NT/2000 :
-> Sous Windows 98,
Modifier le fichier autoexec.bat par l'intermédiaire de l'Utilitaire de
configuration système : cliquez sur Démarrer > Programmes >
Accessoires > Outils système > Informations système. Sélectionnez
ensuite Utilitaire de configuration système dans le menu Outils. Activez
l'onglet Autoexec.bat. Vous pouvez modifier une variable existante ou en
ajouter une nouvelle en cliquant sur le bouton Nouveau.
-> Sous Windows NT/2000, il est préférable d'effectuer les modifications de
variables d'environnement depuis le Panneau de configuration. Ouvrez ce
dernier, et double-cliquez sur l'icône Système. Editez ensuite les variables
d'environnement comme indiqué précédemment.
Il suffit de rajouter le chemin de recherche dans le path par exemple : C:\j2sdk1.4.2_04\bin
pour les binaires.
Pour travailler efficacement je vous propose d'utiliser le logiciel Eclipse. Vous le télécharger à cette adresse. Il offre l'avantage d'être gratuit et permet la construction de projet global et surtout propose toutes les fonctions par défaut lors de la frappe (fini les erreurs de syntaxes) J'y reviendrai plus tard ...
Figure 1. Cycle de développement d'une applet
Figure 1. Cycle de développement d'une applet
Ce programme doir avoir comme nom : HelloWorld.java (on utilise un éditeur
comme notepad)
public class HelloWorld
{
{
System.out.println ("Hello World !");
}
On le compile par javac HelloWorld.java
On l’exécute par : java HelloWorld
On obtient : Hello World !
import java.applet.Applet;
import java.awt.Graphics;
public
class HelloWorld extends Applet
{
public void paint (Graphics g)
{
g.drawString("Hello world !", 50, 20);
}
public static void main (String [ ] args)
{
System.out.println ("Hello World !");
}
On créé un fichier lance.html :
<HTML>
<HEAD>
<TITLE>Exemple d'applet HelloWorld</TITLE>
</HEAD>
<BODY>
<APPLET CODE="HelloWorld" WIDTH=150 HEIGHT=25>
</APPLET>
</BODY>
On le compile par javac HelloWorld.java
On test l’applet par : appletviewer lance.html
On peut le lancer dans un navigateur en cliquant sur lance.html
On obtient :
Dans l'applet hello World
Passage
de paramètres dans une applet
Le but est de passer des paramètres à une applet, dans notre cas la
valeur toto si rien n'est passé l'applet affiche "hello personne"
On construit une fichier .java que le compile (en .class) -> Java/src/ToujoursHelloApplet.java.txt
Et un fichier .html -> Applet Hello !
On obtient : Applet Hello !
Fonctions polymorphes (le
polymorphisme c'est quoi ?)
On a plusieurs constructeurs définis différemment.
Un exemple : Java/src/MyRect2.java.txt
On obtient :
Calling with coordinates 25,25,50,50 :
My Rect :<25,25,50,50>
Calling with point(10,10) point(20,20) :
My Rect :<10,10,20,20>
Calling with point(10,10) long 50 , haut : 50
My Rect :<10,10,60,60>
L'utilisation du package graphique awt
On utilise le package graphique awt pour créer des menus des boutons ...
Voir : Java/src/Men.java.txt
On obtient :
La
notion d'interface
Nous allons donc créer deux types d'appareils électriques, les
radios et les lampes. Ces deux types implémentent l'interface appareilElectrique
.
Nous allons également créer une classe rallongeElectrique
, qui
est aussi un appareil électrique. La méthode la plus intéressante de cette
classe est la méthode branche(appareilElectrique)
. Celle-ci
enregistre l'objet fourni en paramètre comme étant l'objet alimenté à
travers la rallonge. Cette rallonge possède un interrupteur, que l'on peut
activer ou désactiver en appelant ses méthodes enclenche()
,
respectivement declenche()
. Lorsque l'on change l'état de
l'interrupteur, on indiquera à l'objet qui en dépend qu'il est ou qu'il n'est
plus alimenté.
Voir : Java/src/appareilElectrique.java.txt
et Java/src/testElectrique.java.txt
On obtient : par java testElectrique
la radio du salon est eteinte
on appuie sur l'interrupteur de la rallonge 1
la radio du salon est maintenant allumee
Gestion
des exeptions
Avant de voir comment traiter les exceptions, regardons à quoi elles
correspondent concrètement, en prenant un exemple très simple où on génère
une exception de division par zéro : Java-a/src/DivParZero.java.txt
on obtient :
java.lang.ArithmeticException: / by zero
at DivParZero.main(DivParZero.java:6)
Exception in thread "main"
-> corrigé en : Java-a/src/DivParZero2.java.txt
On obtient :
Une exception arithmétique a été levée
Message : / by zero
Pile :
java.lang.ArithmeticException: / by zero
at DivParZero2.main(DivParZero2.java:7)
Avant de voir comment déclarer une exception dans une méthode, il faut savoir comment en lever une. Java définit pour ce faire un mot clé throw qui permet de lever une exception. Par exemple, si nous ajoutons dans notre programme la ligne suivante juste avant le calcul provoquant l'exception arithmétique (dans le bloc try):
if (zero==0 ) throw new ArithmeticException ("Division par zéro");
On obtient :
Une exception arithmétique a été levée
Message : Division par zéro
Pile :
java.lang.ArithmeticException: Division par zéro
at DivParZero.main(DivParZero.java:8)
Les entrées sorties (Supprimer des fichiers temporaires
?)
Un exemple de suppression des fichiers de spool sur un serveur Windows
2000 Terminal server.
: Java/src/DetruitSpoolTSE.java.txt
On obtient : -> plus de fichier dans c:\WINNT\system32\spool\PRINTERS
Lecture
E/S par ligne avec gestion des exceptions
On se sert du package java.io et des classes BufferReader
Voir : Java/src/LectureLigne.java.txt
On obtient par java LectureLigne toto le contenu du ficher toto à l'écran.
Lecture
E/S par caractères avec gestion des exceptions
Voir : Java/src/LireEcrireTexte.java.txt
On obtient par java LireEcrireLigne la copie du fichier
"essai.txt" en "copie essai.txt" avec ajout dans le fichier
"copie essai.txt" du texte /Copie de essai.txt/.
Gestion
de tâches ou thread
Exemple : Java-a/src/LanceCompteurs.java.txt
On obtient : Java-a/src/OutputLanceCompteurs.txt
Ces threads sont démarrés grâce à l'appel de la méthode start(),
héritée de la classe Thread. La Machine Virtuelle exécute alors la méthode run()
que nous avons redéfinie dans le classe ThreadCompteur. Nous passons alors à
l'état exécutable/exécuté (quand le thread est choisi par le gestionnaire de
la JVM).
- Le problème des partages de données :
Exemple : Java-a/src/Compter.java.txt
La classe Compter quant à elle lance deux threads qui vont tout deux appeler la
fonction comptons() sur le même objet. Notons que cette fois-ci, nous
attendons que les deux threads aient terminé leur exécution en faisant appel
à la méthode join() héritée de la classe Thread. Cette méthode rend
la main quand l'objet thread sur lequel elle est appliquée a terminé son
travail (fin de la méthode run() par exemple).
On obtient : Java-a/src/Outpout-Compter.txt
au lieu de 100000000 et 200000000
On corrige par :
Si nous mettons ce mot clé devant la définition de la fonction comptons() synchronized
void comptons()
nous obtenons à l'écran :
Total : 100000000
Total : 200000000
Gestion
réseau via les URL
Java permet d'utiliser des URL, lors de la désignation d'une
ressource, ce qui simplifie grandement la programmation de certaines
applications. Regardons comment ces URL sont utilisées en Java, en prenant
l'exemple d'un programme qui récupère un fichier sur un serveur web et qui en
affiche le contenu à l'écran :
voir : Java-a/src/GetURL.java.txt
On le lance par :
java GetURL http://www.truc.com/index.html et on obtient le contenu de la page.
Gestion
de fenêtres
Il existe principalement deux types de containers. Ceux de type Panel,
permettant de disposer des groupes d'éléments dans une fenêtre, et Window
pour définir des fenêtres principales (Frame) ou des fenêtres de
dialogue (Dialog).
Etudions maitenant les layouts :
BorderLayout : ce manager permet de spécifier l'une des quatre positions
cardinales, en plus du centre, afin d'indiquer dans quelle zone du container on
désire ajouter un composant.
FlowLayout : positionne horizontalement les composants qu'on lui donne,
en passant à la ligne suivante quand on arrive en fin d'une ligne.
GridLayout : dispose les composants dans une grille dont chaque case a la
même taille.
CardLayout : est plutôt utilisé pour disposer des containers que des
composants, sous forme de pile, de telle façon que seul le 1er soit
visible.
Il est important de noter que, pour une fenêtre, le layout par défaut est le
BorderLayout.
Voir : Java-a/src/Interface.java.txt
Ensuite, nous indiquons à quel endroit de la fenêtre on désire mettre le
Panel (win.add ("Center", p);), en l'occurrence, au centre. Enfin,
nous faisons appel à deux méthodes, show(), permettant d'afficher la
fenêtre à l'écran et pack() qui est utilisé pour demander au Layout
Manager de disposer les composants le mieux possible.
On obtient :
Accès
aux base de données
Une base de données est identifiée par une URL particulière qui
contient trois champs
un champ protocole ayant pour valeur "jdbc",un sous-protocole,
contenant le nom du driver utilisé. Le premier driver disponible est
"odbc" (via un pont jdbc-odbc), vu que JDBC s'en est inspiré.
un identifiant de base de données.
Exemple d'URL :
jdbc:odbc:mabase
Le package contenant les différentes classes exploitées par JDBC est
java.sql.
On distingue trois étapes permettant de travailler sur une base de données :
Etablissement de la connexion avec la base de données.
Envoi de la requête SQL à cette base.
Traitement du résultat de cette requête
L'établissement de la connexion s'effectue en appelant la méthode getConnection()
de la classe DriverManager, comme suit :
Connection con = DriverManager.getConnection (
"jdbc:odbc:mabase", "login", "mot de passe");
L'établissement de la connexion s'effectue en appelant la méthode getConnection()
de la classe DriverManager, comme suit :
Connection con = DriverManager.getConnection (
"jdbc:odbc:mabase", "login", "mot de passe");
Cette méthode renvoie un objet Connection qui sera exploité pour
l'envoi de la requête. On spécifie dans l'appel de getConnection()
l'URL de la base, un nom d'utilisateur et un mot de passe. Une exception est
levée en cas d'impossibilité d'accès à la base.
Ensuite, on prépare la requête SQL à exécuter sur la base. Pour ce faire, on
crée tout d'abord un objet Statement, grâce à la méthode createStatement()
de la classe Connection :
Il faut charger le driver jdbc de la base. Pour Oracle on récupère suite à
une installation fictive sur un poste le répertoire jdbc créé lors de cette
installation.
Dans notre cas il faut rajouter la variable système.
CLASSPATH=.;c:\jdbc\classes111.zip
On a : Java-a/src/jdbctest.java.txt
On obtient : Java-a/src/outpout-testjdbc.txt
Avec un interface graphique, on rajoute un élément JTextArea et displayText.append(s + " "+ t+ "\n");
on a : Java-a/src/jdbcwin.java.txt
On obtient :
Gestion
des sockets Client -> Serveur
l'interface socket est le
plus largement utilisé pour faire des accès TCP/IP
Une adaptation complète de cette interface a été réalisée dans le langage
Java
classes
Socket,
ServerSocket, DatagramSocket, DatagramPacket
Voir : Java/src/SocketClient.java.txt
et Java/src/SocketServer.java.txt
On remarque :
Coté serveur : Fonctionne
de la même façon que Socket contient en plus la méthode accept() permettant
aux serveurs d'écouter si un client se connecte sur un port
ServerSocket leServerSocket = new ServerSocket(port);
leServerSocket.accept(); // écoute
le "port"
On instantie le socket server, on accept puis on
crée les buffers d’entrées et de sorties.
Coté
client : La communication par flots de données est moins rapide mais
plus fiable.
Socket est utilisée
du coté du client pour ouvrir une connexion pour
créer une nouvelle instance de la classe Socket
Socket laSocket = new Socket(host, port); Utiliser
ensuite les flux pour faire des entrées/sorties
Exemple :
DataInputStream in ;
in = new DataInputStream(new BufferedInputStream(laSocket.getInputStream())); DataOutputStream out ;
out = new DataOutputStream(new BufferedOutputStream(laSocket.getOutputStream()));
A la fin, ne pas
oublier de fermer la connexion
laSocket.close();
On obtient :
et
Gestion
des sockets Clients (+sieurs) -> Serveur
Coté client identique :
Coté serveur : Interface spécifique runnable :
Cette interface vous demande d'implémenter une unique fonction : la
fonction run. La classe abstraite Thread implémente donc (quoi que !!) cette
interface. La différence réside dans le fait qu'un même objet de cette classe
va pouvoir lancer plusieurs threads sur la même méthode run
Coté serveur : Java/src/SocketThrdServer.java.txt
On obtient :
et :
Gestion
des communications (UDP: datagrammes)
Métaphore de base écrire
un message (a), le
mettre dans l'enveloppe avec l'adresse (b)
et utiliser un coursier chargé de transporter le message à destination (c)
Pour l'envoi
créer une
instance de la classe java.net.DatagramPacket
(c)
et y mettre :
un paquet de données
(a)
l'adresse de destination (b)
utiliser la classe java.net.InetAdress
(adresses Internet)
Pour la réception
(idem) créer une
instance de la classe java.net.DatagramPacket (c)
qui sera chargée d'attendre
l'arrivée d'un message sur le port de la machine où le message est attendu.
Chaque paquet de données
contient son adresse de destination pas de vérification d'arrivée des paquets
UDP est un protocole plus rapide mais moins fiable que TCP plus adapté pour la
transmission d'audio ou de vidéo "en direct" si un paquet est perdu
ou en retard, on continue le traitement des autres
Ainsi, on n'instancie pas de Socket (comme pour les flots de données) mais un
DatagramSocket Pas d'utilisation de streams rangement des données dans un
DatagramPacket avec l'adresse de destination chaque paquet est "routé"
de façon indépendante
on demande au DatagramSocket d'envoyer le tout
Exemple
DatagramSocket socketUDP = new DatagramSocket();
DatagramPacket paquet
=new DatagramPacket(donnees, tailleDesDonnees, adresseDestinataire,
portDestinataire);
socketUDP.send(paquet);
Un exemple :
Composé de deux classes comportant chacune une méthode main
EnvoiMessage.java
ReceptionMessage.java
Le programme EnvoiMessage.java est chargé d'envoyer des datagrammes à un
programme tournant sur une autre machine dont le nom doit être indiqué sur la
ligne de commande
suivi du numéro de port . Doit
être compris entre 1024 et 65535
Ensuite attente d'un accusé de réception Le programme ReceptionMessage Reçoit
les messages sur le port prévu à cet effet Les affiche à l'écran (avec
l'adresse et le n° de port d'origine du message) Envoi un accusé de réception
Voir : Java/src/EnvoiMessage.java.txt et
Java/src/ReceptionMessage.java.txt
si on lance sur la
machine tintin la commande
java ReceptionMessage 9999
puis si, sur la machine spirou, on lance la commande
java EnvoiMessage tintin.ens-lyon.fr 9999 puis on tape « Bonjour,
comment allez-vous ? «
Sur la machine tintin, on obtient :
« Réception du port 1027 de la machine spirou.ens-lyon.fr: Bonjour,
comment allez-vous ? «
et sur spirou :
Port local :1027
Du port 9999 de la machine tintin.ens-lyon.fr: accuse de réception
Gestions
des sockets
Le programme peut jouer le rôle de client ou de serveur, on le lance
sur deux machines distinctes d'un réseau.
On remarque :
- Coté serveur : on définit un port d'écoute ici 12345 et on se sert
des fonctionnalités socket de java.
- Coté client : il a seulement besoin de savoir a qui il s'adresse et sur quel
port il doit envoyer les données.
Voir : Java/src/DiscussionSocket.java.txt
On obtient sur les deux machines :
On lance sur les deux machines : java DiscussionSocket
On tape le nom de machine
distante.
Le texte tapé dans la partie "texte du message à envoyer" apparaît
sur le poste distant dans la partie "réception du message"
Applications
distribuées, objets distants, RMI
Moyen : le RPC
Remote Procedure Call
Dispositif conceptuel permettant qu'un objet d'un programme s'exécutant sur une
machine puisse invoquer un objet d'un autre programme s'exécutant sur une autre
machine
CORBA
Common Object Request Broker Architecture
Est une norme
formalisation du principe du RPC
indépendamment des SE et langages
Promu par l'OMG
RMI
Remote Method Invocation
Est une API
implémentation du RPC dans l'univers Java
Propriété de Sun
RMI est une API de communication entre objets distants
Propre à Java (core API)
Possédant ses propres interfaces, classes, exceptions, sous-paquetages…
Le paquetage java.RMI
Doté d'une gestion de la sécurité (RMISecurityManager)
Construit au-dessus de TCP/IP
Utilisant les sockets
Utilisant donc la sérialisation
Rassemblant la plupart des caractéristiques de CORBA
Mais beaucoup plus simple (Univers Java)
Mais aussi beaucoup plus lent…
Son intérêt : décharger le développeur d'un certain nombre de tâches
fastidieuses et répétitives :
ouverture de sockets, création d'un protocole de communication spécifique,
gestion du multi-threading, envoi des demandes avec encodage des données,
décodage des données, et encodage de la réponse, décodage de la réponse
Côté serveur
Un programme serveur particulier appelé rmiregistry tourne sur la machine
hébergeant le serveur
Ce programme prend en charge les connexions TCP
ouvre un ServerSocket et se met en attente
Tient un registre des objets en cours d'exécution (registry)
Pour assurer la liaison entre objets distants
N'est lancé qu'une seule fois
rend les services attendus tant qu'il n'est pas arrêté par l'administrateur du
serveur
L'objet serveur s'enregistre auprès de rmiregistry
il est dès lors utilisable par des clients via le registre
Le client
Demande au serveur rmi de donner une instance de l'objet serveur
Envoie des messages à cette instance
Comme à tout autre objet
Qui les traite…
Assurent le pont entre
les procédures conventionnelles
d'appel de procédure, côté client
de procédure appelée, côté serveur
et le mécanisme d'accès distant
Un "stub" pour le client, un "skeleton" pour le serveur
Côté client, offre une image de l'objet serveur
Côté serveur, la réciproque
Ainsi, les applications "discutent" par stub et skeleton interposés
NB :
1) depuis le jdk 1.2, seul le stub du client est utilisé
2) un fichier "stub" a donc deux parties :
une partie commune à toutes les applications
consistant en l'établissement d'une communication client/serveur
une partie propre à chaque application
fournissant une interface avec celle-ci
Exemple :
Etape 1 : Définir son interface (au sens Java)
Etape 2 : Côté serveur
implémenter l'objet distribué
En particulier : implémenter l'interface, étendre UnicastRemoteObjects
Lancer "de l'intérieur" le service d'association de ports (rmiregistry)
(facultatif)
Créer l'objet et l'attacher à une URL
Par la méthode Naming.rebind()
Etape 3 : toujours côté serveur
générer le stub
utilisation du programme rmic
Etape 4 : création du fichier de permission côté serveur
Etape 5 : lancement du serveur
Etape 6 : Côté client
attacher l'objet distribué à son espace d'adressage
Par la méthode Naming.lookup()
Un objet distribué se manipule ensuite comme tout autre objet Java
Important :
Les classes d'objets distants doivent implémenter l'interface java.rmi.Remote
Une méthode pouvant être invoquée à distance doit prendre en compte (lever
ou passer) l'exception java.rmi.RemoteException
tout appel distant de méthode risquant d'être interrompu pour x raisons…
java.rmi.RMISecurityManager : contient un gestionnaire de sécurité permettant
de télécharger des objets avec une sécurité suffisante
java.rmi.server.UnicastRemoteObject
Contient les fonctionnalités nécessaires pour effectuer une communication d'un
site à un autre fondé sur le système de communication par sockets de RMI
étant RemoteServer qui étant RemoteObject qui implémente Serializable et
Remote
rebind()
Méthode statique de java.rmi.Naming
Sert à enregistrer l'objet serveur sur le registre RMI
Le nom utilisé pour l'enregistrement est une chaîne de caractères
représentant une URL d'accès
La forme générale est rmi://host:port/name
Le nom de l'hôte par défaut est celui de la machine locale
le port par défaut est 1099
Remarques concernant : lancerRegistry() et throws java.rmi.RemoteException
Appel du programme rmic :
c:\jdk1.3\bin\rmic ServeurDuCompte
Dont le résultat est la création des deux fichiers suivants :
ServeurDuCompte_Stub.class
ServeurDuCompte_Skel.class
et dont seul le stub est utilisé (depuis Java 2)
Il doit être atteignable par la JVM aussi bien côté serveur que client
Dans le dossier du programme ou par classpath
Etape 4 : nécessité d'indiquer un "fichier de permission" au
déclenchement de l'exécution par une option d'exécution
Créer un fichier, nommé par exemple java.permissions
Contenant :
grant { permission java.security.AllPermission; };
Etape 5 : Déclenchement du serveur
En deux sous-étapes :
1) lancement de rmiregistry avec le numéro du port du serveur
2) lancement du serveur
rmiregistry 1234 (nécessaire uniquement si non inclus dans le code du serveur
…)
java -Djava.security.policy=java.permissions ServeurDuCompte
Sur le serveur :
Programme ServeurDucompte.java : Java/src/ServeurDuCompte.java.txt
Programme java.permissions : grant { permission
java.security.AllPermission; };
Et le programme ServeurDuCompte_Stub.class
Sur le client :
Programme Client.java : Java/src/Client.java.txt
Et le programme ServeurDuCompte_Stub.class
Sur client et serveur :
Programme CompteDistant.java :
public interface CompteDistant extends java.rmi.Remote {
float depot(float amount) throws java.rmi.RemoteException;
float retrait(float amount) throws java.rmi.RemoteException;
float litSolde() throws java.rmi.RemoteException;
}
Sur le serveur :
On lance : rmic ServeurDuCompte puis java -Djava.security.policy=java.permissions
ServeurDuCompte on obtient : Enregistrement du serveur
Sur le client :
On lance : java Client on obtient : Sortie 9876.0 (!!!)