Examen de Java
Correction
FIUPSO 3/DESS – Année 2001/2002
Hugues MOUNIER
1 février 2002
Modalités
– Durée : 4 heures
– Tous les documents sont autorisés.
– Les sources java répondant à chaque exercice, et seulement les sources seront obli-
gatoirement copiés dans le répertoire examenjava (tout en minuscules) crée à la
racine de votre compte.
Solution de l’ex. 1 Calculatrice
Voici une solution possible :
// Gestion simpliste de banque utilisant des sockets
import java.util.*;
import java.io.*;
public class Calculette {
static double resultat = 0;
/ methodes /
static int somme(int a, int b) { return(a+b); }
static int soustraction(int a, int b) { return(a-b); }
static int multiplication(int a, int b) { return(a*b); }
static double division(int a, int b) { return(a/b); }
public static void main(String args[]) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
// Boucle infinie
for(;;) {
try {
// Afficher une invite a l’utilisateur
System.out.println("1 Somme de deux entiers\n" +
"2 Soustraction de deux entiers\n" +
"3 Multiplication de deux entiers\n" +
"4 Division de deux entiers\n" +
"5 Sortie du programme\n\n" +
"Veuillez entrer votre choix :\n");
// Lire une ligne entree par l’utilisateur
String line = in.readLine();
1
Examen Java
FIUPSO 3/DESS
2001/2002
entre "quit", on sort
// Si l’on rencontre une fin de fichier, ou si l’utilisateur
//
if ((line == null) || line.equals("5")) break;
// On essaie de formatter l’entree de l’utilisateur,
int choix = Integer.parseInt(line);
System.out.print("Veuillez entrer le 1er entier : ");
line = in.readLine();
int x = Integer.parseInt(line);
System.out.print("Veuillez entrer le 2eme entier : ");
line = in.readLine();
int y = Integer.parseInt(line);
switch(choix) {
case 1 : resultat = somme(x, y); // Somme
case 2 : resultat = soustraction(x, y); // Soustraction
break;
break;
case 3 : resultat = multiplication(x, y); // Multiplication
case 4 : resultat = division(x, y); // Division
break;
}
System.out.println("Resultat : " + resultat);
break;
}
// Affichage d’un message d’erreur en cas de probleme
catch(Exception e) { System.out.println("Entree Invalide"); }
}
}
}
Gestion de banque en client/serveur par sockets
L’objet des exercices qui suivent est de développer une application de gestion bancaire
simple en réseau, utilisant les sockets. Ce dernier mécanisme n’offrant que du transfert de
flux, donc d’assez bas niveau, il est nécessaire de concevoir un protocole permettant de
différentier les différentes opérations bancaires tout en acheminant les données pertinentes.
Ce type de conception ne serait pas nécessaire si l’on prenait des invocations de méthodes
distantes (RMI), bien que l’on perde évidemment en souplesse de conception.
Pour réaliser l’objectif visé, on se fondera sur l’exercice de gestion bancaire en local. On
représentera un paquet par une classe décrite ci-dessous.
Solution de l’ex. 2 Paquets à échanger
Une solution possible est la suivante :
// Gestion simpliste de banque utilisant des sockets
import java.util.*;
import java.io.*;
/**
- Classe pour stocker les donnees d’un compte bancaire
**/
class Account {
String password;
int
Vector transactions = new Vector();
balance;
// mot de passe
// solde du compte
// historique des transactions
Hugues MOUNIER
2
Examen Java
FIUPSO 3/DESS
2001/2002
Account(String password) {
this.password = password;
this.balance = 0;
transactions.addElement("Compte ouvert le " + new Date());
}
}
/**
- Classe representant un paquet du protocoloe bancaire
**/
public class BankSocketPacket {
String
int
String
int
name;
operation;
password;
amount;
// nom du compte
// operation bancaire
// mot de passe
// solde
/ Operations /
public static final int OPEN
public static final int CLOSE
public static final int DEPOSIT
public static final int WITHDRAW
public static final int BALANCE
public static final int QUIT
/ Erreurs /
public static final int TRANSOK
public static final int EXISTANT
public static final int NONEXISTANT = -2; // Operation sur compte inexistant
public static final int INVPASSWORD = -3; // Mot de passe invalide
public static final int NEGBALANCE
// Ouverture de compte
// Fermeture de compte
// Depot sur un compte
// Retrait sur un compte
// Solde d’un compte
// Sortie du programme
= 0;
= -1; // Overture de compte deja existant
= -4; // Solde insuffisant pour retrait
= 1;
= 2;
= 3;
= 4;
= 5;
= 6;
// Transaction bien passee
BankSocketPacket(String theName, int theOperation,
String thePassword, int theAmount) {
= theName;
name
operation = theOperation;
password = thePassword;
amount
= theAmount;
}
public String foldPacket() {
String
StringBuffer
foldedPacket;
tobeFolded = new StringBuffer();
tobeFolded.append(this.name).append(":");
Integer opCode = new Integer(this.operation);
tobeFolded.append(opCode.toString());
if (password != null) {
tobeFolded.append(":").append(this.password);
}
}
tobeFolded.append(":").append(this.amount);
tobeFolded.append("#");
foldedPacket = new String(tobeFolded);
return(foldedPacket);
public void unfoldPacket(String foldedPacket) {
Hugues MOUNIER
3
Examen Java
FIUPSO 3/DESS
2001/2002
String
unfoldedTab[] = new String[4];
Publicité
/ Le deballage est d’abord effectue dans un tableau de String /
int current = foldedPacket.indexOf(’:’, 0);
int next
int last
int i
= foldedPacket.indexOf(’:’, current+1);
= current;
= 1;
unfoldedTab[0] = foldedPacket.substring(0, current);
while (next != -1) {
unfoldedTab[i++] = foldedPacket.substring(current+1, next);
last
= current;
current = foldedPacket.indexOf(’:’, last+1);
next
= foldedPacket.indexOf(’:’, current+1);
}
unfoldedTab[i] = foldedPacket.substring(current+1, foldedPacket.length()-1);
/ On remplit les champs du paquet deballe /
try {
name = new String(unfoldedTab[0]);
operation = Integer.parseInt(unfoldedTab[1]);
password = new String(unfoldedTab[2]);
amount = Integer.parseInt(unfoldedTab[3]);
} catch (NumberFormatException e) {
System.err.println("Erreur en unfoldPacket()--parseInt() : ");
System.err.println(e);
System.exit(1);
}
}
/ Test /
/*
public static void main(String[] args) {
Account cpte = new Account("issos");
BankSocketPacket packet = new BankSocketPacket("Alexandre", cpte, OPEN);
String aAfficher = packet.foldPacket();
System.out.println(aAfficher);
String[] deballe = BankSocketPacket.unfoldPacket(aAfficher);
for(int i = 0; i < deballe.length; i++)
System.out.println(deballe[i]);
}
*/
}
Solution de l’ex. 3 Élaboration du serveur
Une solution possible est la suivante :
// Serveur Bancaire simpliste en sockets
import java.util.*;
import java.io.*;
import java.net.*;
/**
- Cette classe implante les methodes distantes definies par l’interface
- RemoteBank. Son plus gros defaut est que toutes les informations sur les
Hugues MOUNIER
4
Examen Java
FIUPSO 3/DESS
2001/2002
- comptes sont perdues lorsque le serveur s’arrete.
**/
public class BankServerSocket
{
public final static int DEFAULT_PORT = 6789;
Hashtable accounts = new Hashtable();
static int transCode;
/**
- Ouvre un compte avec le nom et le mot de passe specifie
- Cette methode est synchronisee de facon qu’une seule thread
- ne modifie a la fois la table des comptes.
**/
public synchronized void openAccount(String name, String password) {
// Verifier s’il exsite deja un compte ayant ce nom
if (accounts.get(name) != null) {
transCode = BankSocketPacket.EXISTANT;
return;
}
// S’il n’existe pas, le creer
Account acct = new Account(password);
// Et l’enregsitrer
accounts.put(name, acct);
transCode = BankSocketPacket.TRANSOK;
}
/**
- Cette methode utilitaire n’est pas une methode accessible de maniere
- distante. Etant donnes un nom et un mot de passe, verifie s’il existe
- un compte correspondant. Si oui, renvoie l’objet Account. Sinon,
- leve une exception.
**/
public Account verify(String name, String password) {
synchronized(accounts) {
Account acct = (Account)accounts.get(name);
if (acct == null) {
transCode = BankSocketPacket.NONEXISTANT;
return null;
}
if (!password.equals(acct.password)) {
transCode = BankSocketPacket.INVPASSWORD;
return null;
}
transCode = BankSocketPacket.TRANSOK;
return acct;
}
}
/**
- Ferme le compte dont on donne le nom. Methode synchronisee
**/
public synchronized FunnyMoney closeAccount(String name, String password) {
Account acct;
acct = verify(name, password);
if (acct != null) {
accounts.remove(name);
synchronized (acct) {
int balance = acct.balance;
Hugues MOUNIER
5
Examen Java
FIUPSO 3/DESS
2001/2002
acct.balance = 0;
return new FunnyMoney(balance);
}
} else
return new FunnyMoney(-1);
}
/* Deposer le montant specifie su le compte dont on donne le nom /
public void deposit(String name, String password, FunnyMoney money) {
Account acct = verify(name, password);
if (acct != null)
synchronized(acct) {
acct.balance += money.amount;
acct.transactions.addElement(money.amount + " pieces deposees le "
+ new Date());
}
}
/* Effectue un retarit d’un montant specifie /
public FunnyMoney withdraw(String name, String password, int amount) {
Account acct = verify(name, password);
if (acct != null)
synchronized(acct) {
if (acct.balance < amount) {
transCode = BankSocketPacket.NEGBALANCE;
return new FunnyMoney(0);
}
acct.balance -= amount;
acct.transactions.addElement("Retrait de " + amount + " le "+new Date());
return new FunnyMoney(amount);
}
else
}
return new FunnyMoney(-1);
/* Renvoie le solde du compte dont on donne le nom /
public int getBalance(String name, String password) {
Account acct = verify(name, password);
if (acct != null)
synchronized(acct) { return acct.balance; }
else
return -1;
}
/**
- Renvoie un vecteur de String contenant l’historique pour
- le compte dont on donne le nom
**/
public Vector getTransactionHistory(String name, String password) {
Account acct = verify(name, password);
synchronized(acct) { return acct.transactions; }
}
void sendPacket(String name, int operation, String password, int amount,
BankSocketPacket toSend = new BankSocketPacket(name, operation, password, amount);
String lineTosend = toSend.foldPacket();
PrintStream out) {
Hugues MOUNIER
6
Examen Java
FIUPSO 3/DESS
2001/2002
out.println(lineTosend);
}
/**
- Serveur bancaire par sockets
**/
public static void main (String[] args) throws IOException {
// no de port du service
int
String
ServerSocket
Socket
DataInputStream in;
PrintStream
out;
port;
lineRecieved = null;
server;
Publicité
client;
String
int
String
int
FunnyMoney
name;
operation;
password;
amount;
money;
// Tests d’arguments
switch(args.length) {
case 0 : port = DEFAULT_PORT;
break;
case 1 : try {
port = Integer.parseInt (args[0]);
} catch (NumberFormatException e) {
port = DEFAULT_PORT;
}
break;
default :
throw new IllegalArgumentException ("Syntaxe : java BankServerSocket [<port>]");
}
// Creation de socket serveur
System.out.println ("Demarrage sur le port " + port);
server = new ServerSocket (port);
System.out.println ("En ecoute ...");
BankServerSocket bank = new BankServerSocket();
// Boucle generale et service
while (true) {
// Acceptation de connexion
client = server.accept();
System.out.println ("Connexion a " + client.getInetAddress() + " acceptee");
System.out.flush();
// Capture des flux de reception et d’envoi
in = new DataInputStream(client.getInputStream());
out = new PrintStream(client.getOutputStream());
//-----------------------
// TRAITEMENT DU SERVICE
//-----------------------
while (true) {
// lire une ligne
lineRecieved = in.readLine();
if ((lineRecieved == null))
break;
Hugues MOUNIER
7
Examen Java
FIUPSO 3/DESS
2001/2002
BankSocketPacket toUnfold = new BankSocketPacket(null, 0, null, 0);
toUnfold.unfoldPacket(lineRecieved);
= toUnfold.name;
name
operation = toUnfold.operation;
password = toUnfold.password;
amount
= toUnfold.amount;
switch(operation) {
case BankSocketPacket.OPEN :
bank.openAccount(name, password);
bank.sendPacket("noname", transCode, "nopass", 0, out);
break;
case BankSocketPacket.CLOSE :
money = bank.closeAccount(name, password);
bank.sendPacket(name, transCode, password, money.amount, out);
break;
case BankSocketPacket.DEPOSIT :
money = new FunnyMoney(amount);
bank.deposit(name, password, money);
bank.sendPacket(name, transCode, password, money.amount, out);
break;
case BankSocketPacket.WITHDRAW :
money = bank.withdraw(name, password, amount);
bank.sendPacket(name, transCode, password, money.amount, out);
break;
case BankSocketPacket.BALANCE :
int amt = bank.getBalance(name, password);
bank.sendPacket(name, transCode, password, amt, out);
break;
case BankSocketPacket.QUIT :
System.out.println ("Fermeture des socket client & serveur");
client.close ();
server.close ();
System.exit(0);
}
}
if (lineRecieved == null) {
// Sortie du service : le client a termine
System.out.println ("Fermeture de socket client");
client.close ();
}
}// while(true)
}/ main() /
}// BankServerSocket
/*
try {
}
catch (Exception e) {
System.err.println(e);
System.err.println("Utilisation : java BankServerSocket");
System.exit(1); // On sort
}
Hugues MOUNIER
8
Examen Java
FIUPSO 3/DESS
2001/2002
*/
Solution de l’ex. 4 Élaboration du client
Une solution possible est la suivante :
// Gestion simpliste de banque en sockets : client
// Historique a terminer ??
import java.util.*;
import java.io.*;
import java.net.*;
/**
- Classes conteneur :
- - FunnyMoney
**/
la monnaie utilisee
/**
- Cette classe simple represente un montant monetaire. N’est qu’un emballage
- d’un entier.
**/
class FunnyMoney {
public int amount;
public FunnyMoney(int amount) { this.amount = amount; }
}
/**
- Client simple interagissant avec un serveur
**/
public class BankSocket {
// Variables de classe constantes : port et machine par defaut
public static final int
public static final String DEFAULT_HOST = "localhost";
DEFAULT_PORT = 6789;
// Methode utilitaire de saisie
public static String getName(BufferedReader in) {
String name = null;
try {
System.out.println("Veuillez entrer le nom du compte : ");
name = new String(in.readLine().toLowerCase());
} catch (IOException e) {
System.err.println("Erreur en readLine()");
}
return name;
}
// Methode utilitaire de saisie
public static String getPassword(BufferedReader in) {
String password = null;
try {
System.out.println("Veuillez entrer le mot de passe : ");
Hugues MOUNIER
9
Examen Java
FIUPSO 3/DESS
2001/2002
password = new String(in.readLine().toLowerCase());
} catch (IOException e) {
System.err.println("Erreur en readLine()");
}
return password;
}
// Methode utilitaire de gestion d’erreur
static void treatError(int errorNb) {
switch(errorNb) {
case BankSocketPacket.EXISTANT
:
System.out.println("Le compte existe deja");
break;
case BankSocketPacket.NONEXISTANT :
System.out.println("Compte inexistant");
break;
case BankSocketPacket.INVPASSWORD :
System.out.println("Mot de passe invalide");
break;
case BankSocketPacket.NEGBALANCE
:
System.out.println("Solde insuffisant");
break;
}
}
// Methode utilitaire d’envoi/reception de paquet
static BankSocketPacket sendReceive(BankSocketPacket toSend,
Publicité
BankSocketPacket unfolded = new BankSocketPacket(null, 0, null, 0);
DataInputStream sin, PrintStream sout, String message) {
String lineTosend = toSend.foldPacket();
sout.println(lineTosend);
try {
String lineRecieved = sin.readLine();
if (lineRecieved != null) {
unfolded.unfoldPacket(lineRecieved);
if (unfolded.operation == BankSocketPacket.TRANSOK)
System.out.println(message);
else
treatError(unfolded.operation);
} else {
}
System.out.println("Serveur arrete ; sortie");
System.exit(1);
} catch (IOException e) {
System.out.println("Erreur en reception de paquet : " +
e.toString());
System.exit(1);
}
return(unfolded);
}
/**
- Programme client
**/
public static void main(String[] args) {
Hugues MOUNIER
10
Examen Java
FIUPSO 3/DESS
2001/2002
try {
port;
= null; // Machine du serveur
String host
int
Socket s
= null;
DataInputStream sin = null;
PrintStream sout
= null;
BufferedReader stdin = null;// Flux associe au clavier
// No de port du serveur (no de service)
// Reference a la socket client
// Flux en provenance du serveur
// Flux a destination du serveur
//
BankSocket b = new BankSocket();
// Tests d’arguments
switch(args.length) {
case 0 : host = new String(DEFAULT_HOST);
port = DEFAULT_PORT;
break;
case 1 : host = new String(args[0]);
port = DEFAULT_PORT;
break;
case 2 : host = new String(args[0]);
try {
port = Integer.parseInt (args[1]);
} catch (NumberFormatException e) {
System.err.println("Numero de port invalide. " +
DEFAULT_PORT + " Utilise.");
port = DEFAULT_PORT;
}
break;
default : System.out.println("Nombre d’arguments illegal");
throw new IllegalArgumentException();
}// switch()
s = new Socket(host, port);
// Creer les flux pour lire et ecrire des lignes de texte
// de et vers cette socket.
sin = new DataInputStream(s.getInputStream());
sout = new PrintStream(s.getOutputStream());
System.out.println("Connecte a " + s.getInetAddress()
+ ":"+ s.getPort());
(par defaut le clavier)
// Creer un flux pour lire des lignes de l’entree standard
//
stdin = new BufferedReader(new InputStreamReader(System.in));
String cmd = "nothing";
while(true) {
System.out.println("\nVeuillez entrer une commande : \n" +
(ouverture de compte)\n" +
(cloture de compte)\n" +
"open
"close
"deposit (depot sur le compte)\n" +
"withdraw (retrait sur le compte)\n" +
"balance (solde du compte)\n" +
"quit
(sortie du programme)\n");
// Convertir la commande utilisateur en minuscules
cmd = stdin.readLine().toLowerCase();
// Differentes actions possibles
if (cmd.equals("open")) {
// ouverture de compte
String name = getName(stdin); String password = getPassword(stdin);
BankSocketPacket packet =
Hugues MOUNIER
11
Examen Java
FIUPSO 3/DESS
2001/2002
new BankSocketPacket(name, BankSocketPacket.OPEN, password, 0);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Compte ouvert.");
}
else if (cmd.equals("close")) {
String name = getName(stdin);
BankSocketPacket packet =
// fermeture de compte
String password = getPassword(stdin);
new BankSocketPacket(name, BankSocketPacket.CLOSE, password, -1);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Solde : ");
System.out.println(unfolded.amount + " pieces rendues.");
System.out.println("Au revoir.");
}
else if (cmd.equals("deposit")) {
String name = getName(stdin);
System.out.println("Veuillez entrer le montant : ");
int amount = Integer.parseInt(stdin.readLine().toLowerCase());
BankSocketPacket packet =
// depot d’argent
String password = getPassword(stdin);
new BankSocketPacket(name, BankSocketPacket.DEPOSIT, password, amount);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Depot realise.");
}
else if (cmd.equals("withdraw")) {
// retrait d’argent
String name = getName(stdin); String password = getPassword(stdin);
System.out.println("Veuillez entrer le montant : ");
int amount = Integer.parseInt(stdin.readLine().toLowerCase());
BankSocketPacket packet =
new BankSocketPacket(name, BankSocketPacket.WITHDRAW, password, amount);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Retrait realise.");
}
else if (cmd.equals("balance")) {
// solde du compte
String name = getName(stdin); String password = getPassword(stdin);
BankSocketPacket packet =
new BankSocketPacket(name, BankSocketPacket.BALANCE, password, -1);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Solde : ");
System.out.println(unfolded.amount + " pieces sur le compte.");
//
//
//
//
}
else if (cmd.equals("history")) {
String name = getName(stdin);
Vector transactions = bank.getTransactionHistory(name, password);
for(int i = 0; i < transactions.size(); i++)
// historique des transactions
String password = getPassword(stdin);
System.out.println(transactions.elementAt(i));
}
else if (cmd.equals("quit")) {
BankSocketPacket packet =
// break
new BankSocketPacket("noname", BankSocketPacket.QUIT, "nopass", -1);
BankSocketPacket unfolded = sendReceive(packet, sin, sout, "Solde : ");
System.out.println("Au revoir\n");
break;
}
else System.out.println("Action inconnue");
}
}// while not quitted
// Exceptions, erreurs de syntaxe, affichage d’utilisation
catch (Exception e) {
System.err.println(e);
System.err.println("Utilisation : java BankLocal");
}
}
}// class Client
Hugues MOUNIER
12
Examen Java
FIUPSO 3/DESS
2001/2002
Hugues MOUNIER
13