Différents langages de programmation (sommaire)

--------------------> Un exemple complet à consulter après la lecture de cette page je pense !

Installation du JDK

Le premier programme

La première applet  

Passage de paramètres dans une applet

Fonctions polymorphes (le polymorphisme c'est quoi ?)

L'utilisation du package graphique awt

La notion d'interface

Gestion des exeptions

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 de tâches ou thread

Gestion réseau via les URL

Gestion de fenêtres

Accès aux base de données 

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


     Installation du SDK
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 ...

 


Cycle de développement d'une applet
Figure 1. Cycle de développement d'une applet

Figure 1. Cycle de développement d'une applet

     Le premier programme
Ce programme doir avoir comme nom : HelloWorld.java (on utilise un éditeur comme notepad)
public class HelloWorld

{      public static void main (String [ ] args)  
  {  
    System.out.println ("Hello World !");  
  }
}
On le compile par javac HelloWorld.java
On l’exécute par : java HelloWorld
On obtient : Hello World !

    
La première applet
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>  
</HTML>
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 . D
oit être compris entre 1024 et 65535
Le message doit ensuite être tapé sur une ligne
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 (!!!)